Hello community, here is the log from the commit of package python-ddt for openSUSE:Factory checked in at 2020-06-05 19:59:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-ddt (Old) and /work/SRC/openSUSE:Factory/.python-ddt.new.3606 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ddt" Fri Jun 5 19:59:18 2020 rev:11 rq:809724 version:1.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-ddt/python-ddt.changes 2020-04-07 10:23:51.905998832 +0200 +++ /work/SRC/openSUSE:Factory/.python-ddt.new.3606/python-ddt.changes 2020-06-05 19:59:20.759758493 +0200 @@ -1,0 +2,11 @@ +Thu May 28 03:09:23 UTC 2020 - Steve Kowalik <[email protected]> + +- Update to 1.4.1: + * Remove nose dependency for good + * Require enum34 for Python 2.x. + * Improved code comments and renamed the test name format enum class + * Use enum instead of bool to allow easier future changes + * Allow index-only test names +- Switch to using %pytest macro now that nose is not required + +------------------------------------------------------------------- Old: ---- ddt-1.3.1.tar.gz New: ---- ddt-1.4.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-ddt.spec ++++++ --- /var/tmp/diff_new_pack.sFIj9H/_old 2020-06-05 19:59:21.291760333 +0200 +++ /var/tmp/diff_new_pack.sFIj9H/_new 2020-06-05 19:59:21.291760333 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %bcond_without python2 Name: python-ddt -Version: 1.3.1 +Version: 1.4.1 Release: 0 Summary: Data-Driven/Decorated Tests License: MIT @@ -31,7 +31,7 @@ BuildArch: noarch # SECTION test requirements BuildRequires: %{python_module PyYAML} -BuildRequires: %{python_module nose} +BuildRequires: %{python_module pytest} %if %{with python2} BuildRequires: python-mock %endif @@ -52,7 +52,7 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -%python_exec setup.py test +%pytest %files %{python_files} %doc CONTRIBUTING.md README.md ++++++ ddt-1.3.1.tar.gz -> ddt-1.4.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ddt-1.3.1/PKG-INFO new/ddt-1.4.1/PKG-INFO --- old/ddt-1.3.1/PKG-INFO 2020-03-18 04:00:13.898331400 +0100 +++ new/ddt-1.4.1/PKG-INFO 2020-05-15 04:43:34.506477800 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: ddt -Version: 1.3.1 +Version: 1.4.1 Summary: Data-Driven/Decorated Tests Home-page: https://github.com/datadriventests/ddt Author: Carles Barrobés diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ddt-1.3.1/ddt.egg-info/PKG-INFO new/ddt-1.4.1/ddt.egg-info/PKG-INFO --- old/ddt-1.3.1/ddt.egg-info/PKG-INFO 2020-03-18 04:00:13.000000000 +0100 +++ new/ddt-1.4.1/ddt.egg-info/PKG-INFO 2020-05-15 04:43:34.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: ddt -Version: 1.3.1 +Version: 1.4.1 Summary: Data-Driven/Decorated Tests Home-page: https://github.com/datadriventests/ddt Author: Carles Barrobés diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ddt-1.3.1/ddt.egg-info/SOURCES.txt new/ddt-1.4.1/ddt.egg-info/SOURCES.txt --- old/ddt-1.3.1/ddt.egg-info/SOURCES.txt 2020-03-18 04:00:13.000000000 +0100 +++ new/ddt-1.4.1/ddt.egg-info/SOURCES.txt 2020-05-15 04:43:34.000000000 +0200 @@ -8,6 +8,7 @@ ddt.egg-info/PKG-INFO ddt.egg-info/SOURCES.txt ddt.egg-info/dependency_links.txt +ddt.egg-info/requires.txt ddt.egg-info/top_level.txt test/__init__.py test/mycode.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ddt-1.3.1/ddt.egg-info/requires.txt new/ddt-1.4.1/ddt.egg-info/requires.txt --- old/ddt-1.3.1/ddt.egg-info/requires.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/ddt-1.4.1/ddt.egg-info/requires.txt 2020-05-15 04:43:34.000000000 +0200 @@ -0,0 +1,3 @@ + +[:python_version < "3"] +enum34 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ddt-1.3.1/ddt.py new/ddt-1.4.1/ddt.py --- old/ddt-1.3.1/ddt.py 2020-03-18 04:00:07.000000000 +0100 +++ new/ddt-1.4.1/ddt.py 2020-05-15 04:43:25.000000000 +0200 @@ -5,11 +5,12 @@ # DDT is licensed under the MIT License, included in # https://github.com/datadriventests/ddt/blob/master/LICENSE.md +import codecs import inspect import json import os import re -import codecs +from enum import Enum, unique from functools import wraps try: @@ -19,7 +20,7 @@ else: _have_yaml = True -__version__ = '1.3.1' +__version__ = '1.4.1' # These attributes will not conflict with any real python attribute # They are added to the decorated test method and processed later @@ -38,6 +39,33 @@ trivial_types = (type(None), bool, int, float, str) +@unique +class TestNameFormat(Enum): + """ + An enum to configure how ``mk_test_name()`` to compose a test name. Given + the following example: + + .. code-block:: python + + @data("a", "b") + def testSomething(self, value): + ... + + if using just ``@ddt`` or together with ``DEFAULT``: + + * ``testSomething_1_a`` + * ``testSomething_2_b`` + + if using ``INDEX_ONLY``: + + * ``testSomething_1`` + * ``testSomething_2`` + + """ + DEFAULT = 0 + INDEX_ONLY = 1 + + def is_trivial(value): if isinstance(value, trivial_types): return True @@ -110,7 +138,7 @@ return wrapper -def mk_test_name(name, value, index=0): +def mk_test_name(name, value, index=0, name_fmt=TestNameFormat.DEFAULT): """ Generate a new name for a test case. @@ -126,11 +154,14 @@ A "trivial" value is a plain scalar, or a tuple or list consisting only of trivial values. + + The test name format is controlled by enum ``TestNameFormat`` as well. See + the enum documentation for further details. """ # Add zeros before index to keep order index = "{0:0{1}}".format(index + 1, index_len) - if not is_trivial(value): + if name_fmt is TestNameFormat.INDEX_ONLY or not is_trivial(value): return "{0}_{1}".format(name, index) try: value = str(value) @@ -263,7 +294,7 @@ return None -def ddt(cls): +def ddt(arg=None, **kwargs): """ Class decorator for subclasses of ``unittest.TestCase``. @@ -286,35 +317,56 @@ for each ``test_name`` key create as many methods in the list of values from the ``data`` key. + Decorating with the keyword argument ``testNameFormat`` can control the + format of the generated test names. For example: + + - ``@ddt(testNameFormat=TestNameFormat.DEFAULT)`` will be index and values. + + - ``@ddt(testNameFormat=TestNameFormat.INDEX_ONLY)`` will be index only. + + - ``@ddt`` is the same as DEFAULT. + """ - for name, func in list(cls.__dict__.items()): - 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_data_docstring = _get_test_data_docstring(func, v) - if hasattr(func, UNPACK_ATTR): - if isinstance(v, tuple) or isinstance(v, list): - add_test( - cls, - test_name, - test_data_docstring, - func, - *v - ) + fmt_test_name = kwargs.get("testNameFormat", TestNameFormat.DEFAULT) + + def wrapper(cls): + for name, func in list(cls.__dict__.items()): + 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, + fmt_test_name + ) + test_data_docstring = _get_test_data_docstring(func, v) + if hasattr(func, UNPACK_ATTR): + if isinstance(v, tuple) or isinstance(v, list): + add_test( + cls, + test_name, + test_data_docstring, + func, + *v + ) + else: + # unpack dictionary + add_test( + cls, + test_name, + test_data_docstring, + func, + **v + ) else: - # unpack dictionary - add_test( - cls, - test_name, - test_data_docstring, - func, - **v - ) - else: - add_test(cls, test_name, test_data_docstring, func, v) - delattr(cls, name) - elif hasattr(func, FILE_ATTR): - file_attr = getattr(func, FILE_ATTR) - process_file_data(cls, name, func, file_attr) - delattr(cls, name) - return cls + add_test(cls, test_name, test_data_docstring, func, v) + delattr(cls, name) + elif hasattr(func, FILE_ATTR): + file_attr = getattr(func, FILE_ATTR) + process_file_data(cls, name, func, file_attr) + delattr(cls, name) + return cls + + # ``arg`` is the unittest's test class when decorating with ``@ddt`` while + # it is ``None`` when decorating a test class with ``@ddt(k=v)``. + return wrapper(arg) if inspect.isclass(arg) else wrapper diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ddt-1.3.1/setup.py new/ddt-1.4.1/setup.py --- old/ddt-1.3.1/setup.py 2020-03-18 04:00:07.000000000 +0100 +++ new/ddt-1.4.1/setup.py 2020-05-15 04:43:25.000000000 +0200 @@ -25,4 +25,6 @@ 'Programming Language :: Python :: 3.5', 'Topic :: Software Development :: Testing', ], + setup_requires=['enum34; python_version < "3"'], + install_requires=['enum34; python_version < "3"'], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ddt-1.3.1/test/test_functional.py new/ddt-1.4.1/test/test_functional.py --- old/ddt-1.3.1/test/test_functional.py 2020-03-18 04:00:07.000000000 +0100 +++ new/ddt-1.4.1/test/test_functional.py 2020-05-15 04:43:25.000000000 +0200 @@ -1,7 +1,7 @@ import os import json from sys import modules - +import pytest import six try: @@ -9,10 +9,7 @@ except ImportError: import mock -from ddt import ddt, data, file_data -from nose.tools import ( - assert_true, assert_equal, assert_is_not_none, assert_raises -) +from ddt import ddt, data, file_data, TestNameFormat from test.mycode import has_three_elements @@ -32,11 +29,35 @@ return value +@ddt(testNameFormat=TestNameFormat.DEFAULT) +class DummyTestNameFormatDefault(object): + """ + Dummy class to test the ddt decorator that generates test names using the + default format (index and values). + """ + + @data("a", "b", "c", "d") + def test_something(self, value): + return value + + +@ddt(testNameFormat=TestNameFormat.INDEX_ONLY) +class DummyTestNameFormatIndexOnly(object): + """ + Dummy class to test the ddt decorator that generates test names using only + the index. + """ + + @data("a", "b", "c", "d") + def test_something(self, value): + return value + + @ddt class DummyInvalidIdentifier(): """ Dummy class to test the data decorator receiving values invalid characters - indentifiers + identifiers """ @data('32v2 g #Gmw845h$W b53wi.') @@ -93,11 +114,11 @@ dh_keys = set(data_hello.__dict__.keys()) post_size = len(data_hello.__dict__) - assert_equal(post_size, pre_size + 1) + assert post_size == pre_size + 1 extra_attrs = dh_keys - keys - assert_equal(len(extra_attrs), 1) + assert len(extra_attrs) == 1 extra_attr = extra_attrs.pop() - assert_equal(getattr(data_hello, extra_attr), (1, 2)) + assert getattr(data_hello, extra_attr) == (1, 2) def test_file_data_decorator_with_dict(): @@ -115,11 +136,12 @@ dh_keys = set(data_hello.__dict__.keys()) post_size = len(data_hello.__dict__) - assert_equal(post_size, pre_size + 1) + assert post_size == pre_size + 1 extra_attrs = dh_keys - keys - assert_equal(len(extra_attrs), 1) + + assert len(extra_attrs) == 1 extra_attr = extra_attrs.pop() - assert_equal(getattr(data_hello, extra_attr), ("test_data_dict.json",)) + assert getattr(data_hello, extra_attr) == ("test_data_dict.json",) def _is_test(x): @@ -131,7 +153,35 @@ Test the ``ddt`` class decorator """ tests = len(list(filter(_is_test, Dummy.__dict__))) - assert_equal(tests, 4) + assert tests == 4 + + +def test_ddt_format_test_name_index_only(): + """ + Test the ``ddt`` class decorator with ``INDEX_ONLY`` test name format + """ + tests = set(filter(_is_test, DummyTestNameFormatIndexOnly.__dict__)) + assert len(tests) == 4 + + indexes = range(1, 5) + dataSets = ["a", "b", "c", "d"] # @data from DummyTestNameFormatIndexOnly + for i, d in zip(indexes, dataSets): + assert ("test_something_{}".format(i) in tests) + assert not ("test_something_{}_{}".format(i, d) in tests) + + +def test_ddt_format_test_name_default(): + """ + Test the ``ddt`` class decorator with ``DEFAULT`` test name format + """ + tests = set(filter(_is_test, DummyTestNameFormatDefault.__dict__)) + assert len(tests) == 4 + + indexes = range(1, 5) + dataSets = ["a", "b", "c", "d"] # @data from DummyTestNameFormatDefault + for i, d in zip(indexes, dataSets): + assert not ("test_something_{}".format(i) in tests) + assert ("test_something_{}_{}".format(i, d) in tests) def test_file_data_test_creation(): @@ -140,7 +190,7 @@ """ tests = len(list(filter(_is_test, FileDataDummy.__dict__))) - assert_equal(tests, 2) + assert tests == 2 def test_file_data_test_names_dict(): @@ -162,7 +212,7 @@ for index, name in enumerate(test_data.keys()) ]) - assert_equal(tests, created_tests) + assert tests == created_tests def test_feed_data_data(): @@ -177,7 +227,7 @@ method = getattr(obj, test) values.append(method()) - assert_equal(set(values), set([1, 2, 3, 4])) + assert set(values) == set([1, 2, 3, 4]) def test_feed_data_file_data(): @@ -192,7 +242,7 @@ method = getattr(obj, test) values.extend(method()) - assert_equal(set(values), set([10, 12, 15, 15, 12, 50])) + assert set(values) == set([10, 12, 15, 15, 12, 50]) def test_feed_data_file_data_missing_json(): @@ -204,7 +254,8 @@ obj = JSONFileDataMissingDummy() for test in tests: method = getattr(obj, test) - assert_raises(ValueError, method) + with pytest.raises(ValueError): + method() def test_feed_data_file_data_missing_yaml(): @@ -216,7 +267,8 @@ obj = YAMLFileDataMissingDummy() for test in tests: method = getattr(obj, test) - assert_raises(ValueError, method) + with pytest.raises(ValueError): + method() def test_ddt_data_name_attribute(): @@ -242,8 +294,8 @@ setattr(Mytest, 'test_hello', data_hello) ddt_mytest = ddt(Mytest) - assert_is_not_none(getattr(ddt_mytest, 'test_hello_1_data1')) - assert_is_not_none(getattr(ddt_mytest, 'test_hello_2_2')) + assert getattr(ddt_mytest, 'test_hello_1_data1') + assert getattr(ddt_mytest, 'test_hello_2_2') def test_ddt_data_doc_attribute(): @@ -282,34 +334,12 @@ setattr(Mytest, 'second_test', data_hello2) ddt_mytest = ddt(Mytest) - assert_equal( - getattr( - getattr(ddt_mytest, 'first_test_1_case1'), '__doc__'), d1.__doc__ - ) - assert_equal( - getattr( - getattr(ddt_mytest, 'first_test_2_case2'), '__doc__'), - func_w_doc.__doc__ - ) - assert_equal( - getattr( - getattr(ddt_mytest, 'first_test_3'), '__doc__'), - func_w_doc.__doc__ - ) - assert_equal( - getattr( - getattr(ddt_mytest, 'second_test_1_case1'), '__doc__'), d1.__doc__ - ) - assert_equal( - getattr( - getattr(ddt_mytest, 'second_test_2_case2'), '__doc__'), - None - ) - assert_equal( - getattr( - getattr(ddt_mytest, 'second_test_3'), '__doc__'), - None - ) + assert getattr(getattr(ddt_mytest, 'first_test_1_case1'), '__doc__') == d1.__doc__ + assert getattr(getattr(ddt_mytest, 'first_test_2_case2'), '__doc__') == func_w_doc.__doc__ + assert getattr(getattr(ddt_mytest, 'first_test_3'), '__doc__') == func_w_doc.__doc__ + assert getattr(getattr(ddt_mytest, 'second_test_1_case1'), '__doc__') == d1.__doc__ + assert getattr(getattr(ddt_mytest, 'second_test_2_case2'), '__doc__') is None + assert getattr(getattr(ddt_mytest, 'second_test_3'), '__doc__') is None def test_ddt_data_unicode(): @@ -326,9 +356,9 @@ def test_hello(self, val): pass - assert_is_not_none(getattr(Mytest, 'test_hello_1_ascii')) - assert_is_not_none(getattr(Mytest, 'test_hello_2_non_ascii__u2603')) - assert_is_not_none(getattr(Mytest, 'test_hello_3')) + assert getattr(Mytest, 'test_hello_1_ascii') is not None + assert getattr(Mytest, 'test_hello_2_non_ascii__u2603') is not None + assert getattr(Mytest, 'test_hello_3') is not None elif six.PY3: @@ -338,9 +368,9 @@ def test_hello(self, val): pass - assert_is_not_none(getattr(Mytest, 'test_hello_1_ascii')) - assert_is_not_none(getattr(Mytest, 'test_hello_2_non_ascii__')) - assert_is_not_none(getattr(Mytest, 'test_hello_3')) + assert getattr(Mytest, 'test_hello_1_ascii') is not None + assert getattr(Mytest, 'test_hello_2_non_ascii__') is not None + assert getattr(Mytest, 'test_hello_3') is not None def test_ddt_data_object(): @@ -353,8 +383,7 @@ @data(object()) def test_object(self, val): pass - - assert_is_not_none(getattr(Mytest, 'test_object_1')) + assert getattr(Mytest, 'test_object_1') is not None def test_feed_data_with_invalid_identifier(): @@ -362,15 +391,12 @@ Test that data is fed to the decorated tests """ tests = list(filter(_is_test, DummyInvalidIdentifier.__dict__)) - assert_equal(len(tests), 1) + assert len(tests) == 1 obj = DummyInvalidIdentifier() method = getattr(obj, tests[0]) - assert_equal( - method.__name__, - 'test_data_with_invalid_identifier_1_32v2_g__Gmw845h_W_b53wi_' - ) - assert_equal(method(), '32v2 g #Gmw845h$W b53wi.') + assert method.__name__ == 'test_data_with_invalid_identifier_1_32v2_g__Gmw845h_W_b53wi_' + assert method() == '32v2 g #Gmw845h$W b53wi.' @mock.patch('ddt._have_yaml', False) @@ -384,14 +410,15 @@ @file_data('data/test_data_dict.yaml') def test_file_data_yaml_dict(self, value): - assert_true(has_three_elements(value)) + assert has_three_elements(value) tests = filter(_is_test, NoYAMLInstalledTest.__dict__) obj = NoYAMLInstalledTest() for test in tests: method = getattr(obj, test) - assert_raises(ValueError, method) + with pytest.raises(ValueError): + method() def test_load_yaml_with_python_tag(): @@ -411,7 +438,7 @@ class YamlDefaultLoaderTest(object): @file_data('data/test_functional_custom_tags.yaml') def test_cls_is_instance(self, cls, expected): - assert_true(isinstance(cls, str_to_type(expected))) + assert isinstance(cls, str_to_type(expected)) except Exception as e: if not isinstance(e, ConstructorError): raise AssertionError() @@ -420,7 +447,7 @@ class YamlFullLoaderTest(object): @file_data('data/test_functional_custom_tags.yaml', FullLoader) def test_cls_is_instance(self, instance, expected): - assert_true(isinstance(instance, str_to_type(expected))) + assert isinstance(instance, str_to_type(expected)) tests = list(filter(_is_test, YamlFullLoaderTest.__dict__)) obj = YamlFullLoaderTest()
