Hello community,

here is the log from the commit of package python-ddt for openSUSE:Factory 
checked in at 2018-08-08 14:53:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ddt (Old)
 and      /work/SRC/openSUSE:Factory/.python-ddt.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ddt"

Wed Aug  8 14:53:45 2018 rev:5 rq:627903 version:1.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ddt/python-ddt.changes    2017-08-24 
18:45:53.200437420 +0200
+++ /work/SRC/openSUSE:Factory/.python-ddt.new/python-ddt.changes       
2018-08-08 14:54:44.229672602 +0200
@@ -1,0 +2,7 @@
+Tue Aug  7 14:48:44 UTC 2018 - [email protected]
+
+- update to 1.2.0
+  * Added individual test case docstring support and tests 
+  * Add nested dict example to docs and cosmetic adjustments
+
+-------------------------------------------------------------------

Old:
----
  ddt-1.1.1.tar.gz

New:
----
  ddt-1.2.0.tar.gz

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

Other differences:
------------------
++++++ python-ddt.spec ++++++
--- /var/tmp/diff_new_pack.oQcONg/_old  2018-08-08 14:54:44.781673514 +0200
+++ /var/tmp/diff_new_pack.oQcONg/_new  2018-08-08 14:54:44.781673514 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-ddt
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 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
@@ -17,9 +17,8 @@
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%bcond_without test
 Name:           python-ddt
-Version:        1.1.1
+Version:        1.2.0
 Release:        0
 Summary:        Data-Driven/Decorated Tests
 License:        MIT
@@ -28,12 +27,14 @@
 Source:         
https://files.pythonhosted.org/packages/source/d/ddt/ddt-%{version}.tar.gz
 BuildRequires:  %{python_module devel}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 # SECTION test requirements
 BuildRequires:  %{python_module PyYAML}
 BuildRequires:  %{python_module mock}
 BuildRequires:  %{python_module nose}
 # /SECTION
+BuildArch:      noarch
 
 %python_subpackages
 
@@ -48,13 +49,14 @@
 
 %install
 %{python_install}
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%{python_exec setup.py test}
+%python_exec setup.py test
 
 %files %{python_files}
-%defattr(-,root,root,-)
+%doc CONTRIBUTING.md README.md
+%license LICENSE.md
 %{python_sitelib}/*
-%doc *.md
 
 %changelog

++++++ ddt-1.1.1.tar.gz -> ddt-1.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/2.0.md new/ddt-1.2.0/2.0.md
--- old/ddt-1.1.1/2.0.md        2016-08-03 23:43:45.000000000 +0200
+++ new/ddt-1.2.0/2.0.md        1970-01-01 01:00:00.000000000 +0100
@@ -1,42 +0,0 @@
-Hi all, thanks for using the library, your contributions, and especially for 
not bitching about me not being very responsive.
-
-I have been giving the future of `ddt` some thought over the past weeks.
-
-To give some background about how `ddt` came to be: I was looking for 
something that gave to unit tests a similar power as to what one could do with 
nosetests generators (which only worked for nose function-based tests): the 
ability to run a test case multiple times with different data. At that time I 
was beginning to learn me some more advanced Python (I had only been using the 
language for a few months) and was exploring the various mechanisms for 
metaprogramming available in the language. I was fascinated that one could add 
methods to a class at runtime, and I wrote this then tiny library that did that.
-
-Over time I've been taking some people's contributions, some of which grew the 
feature set into areas I hadn't even considered (like reading data from files) 
- but in honesty, that tiny initial feature has been enough for me and is about 
the only one I've actually personally used from the library.
-
-This has unfortunately meant that I've not always been paying as much 
attention as I should have to backwards compatibility of certain features 
(which made some people not particularly happy) or simplifying extensibility in 
general.
-
-Back from that digression, I've often thought that I wanted `ddt` to go back 
to its simpler origins, but still be easily applicable to other people's more 
complex use cases. One of the design decisions I've come to regret the most 
about `ddt` has been using `*args` as the mechanism to pass test data to the 
test methods, because that limits the potential for the API to grow quite a bit.
-
-My current thinking of what the new ddt should look like is:
-
-- keep the class decorator `ddt`
-- a single method decorator that takes test data as an iterable (e.g. similar 
to the one proposed in https://github.com/txels/ddt/pull/40), and options as 
keyword arguments. A well defined mechanism would tell ddt how to generate 
suffixes for the test cases from the test data.
-- get rid of all the other decorators for unpacking, reading from file etc.
-  - the unpacking options would become keyword arguments to the main decorator 
(e.g. `unpack`, `unpack_dict` or similar...)
-  - the methods to read from file etc would be just methods that read from a 
file and return some iterable over the data
-
-E.g. assuming we call the new decorator `idata`, it would look like:
-
-```
-@idata(test_data, **options)
-def test_something(self, value):
-```
-
-E.g. in a practical use:
-
-```
-@idata(from_file('something.yml'), unpack=TUPLE)
-def test_something(self, x, y, z):
-```
-
-```
-@idata(some_dict, unpack=DICT)
-def test_something_else(self, x, y, result):
-```
-
-
-
-Requested features like cartesian products or even additional boundary test 
data generation could easily be added as just plain functions with whatever 
arguments that return an iterable.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/CONTRIBUTING.md 
new/ddt-1.2.0/CONTRIBUTING.md
--- old/ddt-1.1.1/CONTRIBUTING.md       2015-01-27 19:38:50.000000000 +0100
+++ new/ddt-1.2.0/CONTRIBUTING.md       2018-05-13 15:48:36.000000000 +0200
@@ -1,9 +1,11 @@
 # Contributing to DDT
 
+## Guidelines
+
 We'll be happy if you want to contribute to the improvement of `ddt`.
 
 Code contributions will take the form of pull requests to
-[the github repo](https://github.com/txels/ddt).
+[the github repo](https://github.com/datadriventests/ddt).
 
 Your PRs are more likely to be merged quickly if:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/PKG-INFO new/ddt-1.2.0/PKG-INFO
--- old/ddt-1.1.1/PKG-INFO      2016-10-07 21:28:35.000000000 +0200
+++ new/ddt-1.2.0/PKG-INFO      2018-07-17 22:52:34.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: ddt
-Version: 1.1.1
+Version: 1.2.0
 Summary: Data-Driven/Decorated Tests
 Home-page: https://github.com/txels/ddt
 Author: Carles Barrobés
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/README.md new/ddt-1.2.0/README.md
--- old/ddt-1.1.1/README.md     2016-05-20 09:33:32.000000000 +0200
+++ new/ddt-1.2.0/README.md     2018-05-13 15:48:37.000000000 +0200
@@ -9,8 +9,8 @@
 by running it with different test data, and make it appear as
 multiple test cases.
 
-Installation
-------------
+# Installation
+
 
 ```pip install ddt```
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/ddt.egg-info/PKG-INFO 
new/ddt-1.2.0/ddt.egg-info/PKG-INFO
--- old/ddt-1.1.1/ddt.egg-info/PKG-INFO 2016-10-07 21:28:34.000000000 +0200
+++ new/ddt-1.2.0/ddt.egg-info/PKG-INFO 2018-07-17 22:52:34.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: ddt
-Version: 1.1.1
+Version: 1.2.0
 Summary: Data-Driven/Decorated Tests
 Home-page: https://github.com/txels/ddt
 Author: Carles Barrobés
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/ddt.egg-info/SOURCES.txt 
new/ddt-1.2.0/ddt.egg-info/SOURCES.txt
--- old/ddt-1.1.1/ddt.egg-info/SOURCES.txt      2016-10-07 21:28:35.000000000 
+0200
+++ new/ddt-1.2.0/ddt.egg-info/SOURCES.txt      2018-07-17 22:52:34.000000000 
+0200
@@ -1,10 +1,8 @@
-2.0.md
 CONTRIBUTING.md
 LICENSE.md
 MANIFEST.in
 README.md
 ddt.py
-pr40.md
 setup.cfg
 setup.py
 ddt.egg-info/PKG-INFO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/ddt.py new/ddt-1.2.0/ddt.py
--- old/ddt-1.1.1/ddt.py        2016-10-07 21:13:28.000000000 +0200
+++ new/ddt-1.2.0/ddt.py        2018-07-17 22:42:05.000000000 +0200
@@ -9,6 +9,7 @@
 import json
 import os
 import re
+import codecs
 from functools import wraps
 
 try:
@@ -18,7 +19,7 @@
 else:
     _have_yaml = True
 
-__version__ = '1.1.1'
+__version__ = '1.2.0'
 
 # These attributes will not conflict with any real python attribute
 # They are added to the decorated test method and processed later
@@ -27,6 +28,7 @@
 DATA_ATTR = '%values'      # store the data the test must run with
 FILE_ATTR = '%file_path'   # store the path to JSON file
 UNPACK_ATTR = '%unpack'    # remember that we have to unpack values
+index_len = 5              # default max length of case index
 
 
 try:
@@ -59,6 +61,8 @@
     Should be added to methods of instances of ``unittest.TestCase``.
 
     """
+    global index_len
+    index_len = len(str(len(values)))
     return idata(values)
 
 
@@ -118,18 +122,20 @@
     only of trivial values.
     """
 
+    # Add zeros before index to keep order
+    index = "{0:0{1}}".format(index + 1, index_len)
     if not is_trivial(value):
-        return "{0}_{1}".format(name, index + 1)
+        return "{0}_{1}".format(name, index)
     try:
         value = str(value)
     except UnicodeEncodeError:
         # fallback for python2
         value = value.encode('ascii', 'backslashreplace')
-    test_name = "{0}_{1}_{2}".format(name, index + 1, value)
-    return re.sub('\W|^(?=\d)', '_', test_name)
+    test_name = "{0}_{1}_{2}".format(name, index, value)
+    return re.sub(r'\W|^(?=\d)', '_', test_name)
 
 
-def feed_data(func, new_name, *args, **kwargs):
+def feed_data(func, new_name, test_docstring, *args, **kwargs):
     """
     This internal method decorator feeds the test data item to the test.
 
@@ -139,19 +145,24 @@
         return func(self, *args, **kwargs)
     wrapper.__name__ = new_name
     wrapper.__wrapped__ = func
-    # Try to call format on the docstring
-    if func.__doc__:
-        try:
-            wrapper.__doc__ = func.__doc__.format(*args, **kwargs)
-        except (IndexError, KeyError):
-            # Maybe the user has added some of the formating strings
-            # unintentionally in the docstring. Do not raise an exception as it
-            # could be that he is not aware of the formating feature.
-            pass
+    # set docstring if exists
+    if test_docstring is not None:
+        wrapper.__doc__ = test_docstring
+    else:
+        # Try to call format on the docstring
+        if func.__doc__:
+            try:
+                wrapper.__doc__ = func.__doc__.format(*args, **kwargs)
+            except (IndexError, KeyError):
+                # Maybe the user has added some of the formating strings
+                # unintentionally in the docstring. Do not raise an exception
+                # as it could be that user is not aware of the
+                # formating feature.
+                pass
     return wrapper
 
 
-def add_test(cls, test_name, func, *args, **kwargs):
+def add_test(cls, test_name, test_docstring, func, *args, **kwargs):
     """
     Add a test case to this class.
 
@@ -159,7 +170,8 @@
     name.
 
     """
-    setattr(cls, test_name, feed_data(func, test_name, *args, **kwargs))
+    setattr(cls, test_name, feed_data(func, test_name, test_docstring,
+            *args, **kwargs))
 
 
 def process_file_data(cls, name, func, file_attr):
@@ -178,7 +190,9 @@
     # If file does not exist, provide an error function instead
     if not os.path.exists(data_file_path):
         test_name = mk_test_name(name, "error")
-        add_test(cls, test_name, create_error_func("%s does not exist"), None)
+        test_docstring = """Error!"""
+        add_test(cls, test_name, test_docstring,
+                 create_error_func("%s does not exist"), None)
         return
 
     _is_yaml_file = data_file_path.endswith((".yml", ".yaml"))
@@ -186,15 +200,17 @@
     # Don't have YAML but want to use YAML file.
     if _is_yaml_file and not _have_yaml:
         test_name = mk_test_name(name, "error")
+        test_docstring = """Error!"""
         add_test(
             cls,
             test_name,
+            test_docstring,
             create_error_func("%s is a YAML file, please install PyYAML"),
             None
         )
         return
 
-    with open(data_file_path) as f:
+    with codecs.open(data_file_path, 'r', 'utf-8') as f:
         # Load the data from YAML or JSON
         if _is_yaml_file:
             data = yaml.safe_load(f)
@@ -217,9 +233,9 @@
             value = elem
             test_name = mk_test_name(name, value, i)
         if isinstance(value, dict):
-            add_test(cls, test_name, func, **value)
+            add_test(cls, test_name, test_name, func, **value)
         else:
-            add_test(cls, test_name, func, value)
+            add_test(cls, test_name, test_name, func, value)
 
 
 def ddt(cls):
@@ -250,14 +266,15 @@
         if hasattr(func, DATA_ATTR):
             for i, v in enumerate(getattr(func, DATA_ATTR)):
                 test_name = mk_test_name(name, getattr(v, "__name__", v), i)
+                test_docstring = getattr(v, "__doc__", None)
                 if hasattr(func, UNPACK_ATTR):
                     if isinstance(v, tuple) or isinstance(v, list):
-                        add_test(cls, test_name, func, *v)
+                        add_test(cls, test_name, test_docstring, func, *v)
                     else:
                         # unpack dictionary
-                        add_test(cls, test_name, func, **v)
+                        add_test(cls, test_name, test_docstring, func, **v)
                 else:
-                    add_test(cls, test_name, func, v)
+                    add_test(cls, test_name, test_docstring, func, v)
             delattr(cls, name)
         elif hasattr(func, FILE_ATTR):
             file_attr = getattr(func, FILE_ATTR)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/pr40.md new/ddt-1.2.0/pr40.md
--- old/ddt-1.1.1/pr40.md       2016-08-03 17:48:15.000000000 +0200
+++ new/ddt-1.2.0/pr40.md       1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-BTW in terms of memory efficiency: since `ddt` is not (nor wants to be) a test 
runner, in order for the test runner to work properly it has to make the class 
look like it has one different test method per data value - these extra methods 
are created dynamically at class load time, not at test execution time. Meaning 
that the whole generator data will have to be materialised in memory anyway, 
hence there will not be the typical memory savings of other scenarios where 
generators are used.
-
-If you need to test with large datasets, `ddt` is not going to be a memory 
efficient approach.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/setup.cfg new/ddt-1.2.0/setup.cfg
--- old/ddt-1.1.1/setup.cfg     2016-10-07 21:28:35.000000000 +0200
+++ new/ddt-1.2.0/setup.cfg     2018-07-17 22:52:34.000000000 +0200
@@ -4,5 +4,4 @@
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/test/test_data_dict_dict.json 
new/ddt-1.2.0/test/test_data_dict_dict.json
--- old/ddt-1.1.1/test/test_data_dict_dict.json 2015-10-26 18:01:56.000000000 
+0100
+++ new/ddt-1.2.0/test/test_data_dict_dict.json 2018-06-25 22:49:05.000000000 
+0200
@@ -19,4 +19,4 @@
         "end": 0.0,
         "value": -0.5
     }
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/test/test_example.py 
new/ddt-1.2.0/test/test_example.py
--- old/ddt-1.1.1/test/test_example.py  2016-05-31 09:26:09.000000000 +0200
+++ new/ddt-1.2.0/test/test_example.py  2018-06-25 22:42:07.000000000 +0200
@@ -26,6 +26,13 @@
     return r
 
 
+def annotated2(listIn, name, docstring):
+    r = Mylist(listIn)
+    setattr(r, "__name__", name)
+    setattr(r, "__doc__", docstring)
+    return r
+
+
 @ddt
 class FooTestCase(unittest.TestCase):
     def test_undecorated(self):
@@ -44,6 +51,14 @@
         a, b = value
         self.assertGreater(a, b)
 
+    @data(annotated2([2, 1], 'Test_case_1', """Test docstring 1"""),
+          annotated2([10, 5], 'Test_case_2', """Test docstring 2"""))
+    def test_greater_with_name_docstring(self, value):
+        a, b = value
+        self.assertGreater(a, b)
+        self.assertIsNotNone(getattr(value, "__name__"))
+        self.assertIsNotNone(getattr(value, "__doc__"))
+
     @file_data("test_data_dict_dict.json")
     def test_file_data_json_dict_dict(self, start, end, value):
         self.assertLess(start, end)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ddt-1.1.1/test/test_functional.py 
new/ddt-1.2.0/test/test_functional.py
--- old/ddt-1.1.1/test/test_functional.py       2016-05-31 09:26:09.000000000 
+0200
+++ new/ddt-1.2.0/test/test_functional.py       2018-07-17 22:32:10.000000000 
+0200
@@ -147,8 +147,9 @@
     tests_dir = os.path.dirname(__file__)
     test_data_path = os.path.join(tests_dir, 'test_data_dict.json')
     test_data = json.loads(open(test_data_path).read())
+    index_len = len(str(len(test_data)))
     created_tests = set([
-        "test_something_again_{0}_{1}".format(index + 1, name)
+        "test_something_again_{0:0{2}}_{1}".format(index + 1, name, index_len)
         for index, name in enumerate(test_data.keys())
     ])
 
@@ -236,6 +237,47 @@
     assert_is_not_none(getattr(ddt_mytest, 'test_hello_2_2'))
 
 
+def test_ddt_data_doc_attribute():
+    """
+    Test the ``__doc__`` attribute handling of ``data`` items with ``ddt``
+    """
+
+    def hello():
+        """testFunctionDocstring {6}
+
+        :param: None
+        :return: None
+        """
+        pass
+
+    class Myint(int):
+        pass
+
+    class Mytest(object):
+        pass
+
+    d1 = Myint(1)
+    d1.__name__ = 'case1'
+    d1.__doc__ = """docstring1"""
+
+    d2 = Myint(2)
+    d2.__name__ = 'case2'
+
+    data_hello = data(d1, d2)(hello)
+    setattr(Mytest, 'test_hello', data_hello)
+    ddt_mytest = ddt(Mytest)
+
+    assert_equal(
+        getattr(
+            getattr(ddt_mytest, 'test_hello_1_case1'), '__doc__'), d1.__doc__
+    )
+    assert_equal(
+        getattr(
+            getattr(ddt_mytest, 'test_hello_2_case2'), '__doc__'),
+        hello.__doc__
+    )
+
+
 def test_ddt_data_unicode():
     """
     Test that unicode strings are converted to function names correctly


Reply via email to