diff --git a/.gitignore b/.gitignore
index b29aa3e..a82433e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ ddt.egg-info/
 /docs/_build/
 .tox
 .ropeproject
+venv/
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 7ef2224..efeae23 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,10 @@
 language: python
 python:
-  #- 2.6
   - 2.7
-  #- 3.2
-  - 3.3
   - 3.4
   - 3.5
 install: pip install -r requirements/test.txt
+
 script:
     - nosetests --with-cov --cover-package=ddt
     - flake8 ddt.py test
diff --git a/ddt.py b/ddt.py
index 60eb1b0..636de02 100644
--- a/ddt.py
+++ b/ddt.py
@@ -19,7 +19,7 @@ except ImportError:  # pragma: no cover
 else:
     _have_yaml = True
 
-__version__ = '1.2.0'
+__version__ = '1.2.1'
 
 # These attributes will not conflict with any real python attribute
 # They are added to the decorated test method and processed later
@@ -135,7 +135,7 @@ def mk_test_name(name, value, index=0):
     return re.sub(r'\W|^(?=\d)', '_', test_name)
 
 
-def feed_data(func, new_name, test_docstring, *args, **kwargs):
+def feed_data(func, new_name, test_data_docstring, *args, **kwargs):
     """
     This internal method decorator feeds the test data item to the test.
 
@@ -146,8 +146,8 @@ def feed_data(func, new_name, test_docstring, *args, **kwargs):
     wrapper.__name__ = new_name
     wrapper.__wrapped__ = func
     # set docstring if exists
-    if test_docstring is not None:
-        wrapper.__doc__ = test_docstring
+    if test_data_docstring is not None:
+        wrapper.__doc__ = test_data_docstring
     else:
         # Try to call format on the docstring
         if func.__doc__:
@@ -177,7 +177,6 @@ def add_test(cls, test_name, test_docstring, func, *args, **kwargs):
 def process_file_data(cls, name, func, file_attr):
     """
     Process the parameter in the `file_data` decorator.
-
     """
     cls_path = os.path.abspath(inspect.getsourcefile(cls))
     data_file_path = os.path.join(os.path.dirname(cls_path), file_attr)
@@ -223,7 +222,6 @@ def process_file_data(cls, name, func, file_attr):
 def _add_tests_from_data(cls, name, func, data):
     """
     Add tests from data loaded from the data file into the class
-
     """
     for i, elem in enumerate(data):
         if isinstance(data, dict):
@@ -238,6 +236,23 @@ def _add_tests_from_data(cls, name, func, data):
             add_test(cls, test_name, test_name, func, value)
 
 
+def _is_primitive(obj):
+    """Finds out if the obj is a "primitive". It is somewhat hacky but it works.
+    """
+    return not hasattr(obj, '__dict__')
+
+
+def _get_test_data_docstring(func, value):
+    """Returns a docstring based on the following resolution strategy:
+    1. Passed value is not a "primitive" and has a docstring, then use it.
+    2. In all other cases return None, i.e the test name is used.
+    """
+    if not _is_primitive(value) and value.__doc__:
+        return value.__doc__
+    else:
+        return None
+
+
 def ddt(cls):
     """
     Class decorator for subclasses of ``unittest.TestCase``.
@@ -266,15 +281,27 @@ def ddt(cls):
         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)
+                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_docstring, func, *v)
+                        add_test(
+                            cls,
+                            test_name,
+                            test_data_docstring,
+                            func,
+                            *v
+                        )
                     else:
                         # unpack dictionary
-                        add_test(cls, test_name, test_docstring, func, **v)
+                        add_test(
+                            cls,
+                            test_name,
+                            test_data_docstring,
+                            func,
+                            **v
+                        )
                 else:
-                    add_test(cls, test_name, test_docstring, func, v)
+                    add_test(cls, test_name, test_data_docstring, func, v)
             delattr(cls, name)
         elif hasattr(func, FILE_ATTR):
             file_attr = getattr(func, FILE_ATTR)
diff --git a/tox.ini b/tox.ini
index 13df3d3..da77f04 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27, py33, py34, py35
+envlist = py27, py34, py35
 
 [testenv]
 deps = 

function ddt 
function ddt    test_docstring = getattr(v, "__doc__", None)，
when  v has attribte， return __doc__ of  v    So that desc of report  is __doc__ of v（list  tuple dict） ,not __doc__ of  testing function
diff --git a/test/test_functional.py b/test/test_functional.py
index 07f326a..5049928 100644
--- a/test/test_functional.py
+++ b/test/test_functional.py
@@ -242,7 +242,7 @@ def test_ddt_data_doc_attribute():
     Test the ``__doc__`` attribute handling of ``data`` items with ``ddt``
     """
 
-    def hello():
+    def func_w_doc():
         """testFunctionDocstring {6}
 
         :param: None
@@ -250,6 +250,9 @@ def test_ddt_data_doc_attribute():
         """
         pass
 
+    def func_wo_doc():
+        pass
+
     class Myint(int):
         pass
 
@@ -263,18 +266,40 @@ def test_ddt_data_doc_attribute():
     d2 = Myint(2)
     d2.__name__ = 'case2'
 
-    data_hello = data(d1, d2)(hello)
-    setattr(Mytest, 'test_hello', data_hello)
+    data_hello = data(d1, d2, {'test': True})(func_w_doc)
+    data_hello2 = data(d1, d2, {'test': True})(func_wo_doc)
+
+    setattr(Mytest, 'first_test', data_hello)
+    setattr(Mytest, 'second_test', data_hello2)
     ddt_mytest = ddt(Mytest)
 
     assert_equal(
         getattr(
-            getattr(ddt_mytest, 'test_hello_1_case1'), '__doc__'), d1.__doc__
+            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, 'test_hello_2_case2'), '__doc__'),
-        hello.__doc__
+            getattr(ddt_mytest, 'second_test_2_case2'), '__doc__'),
+        None
+    )
+    assert_equal(
+        getattr(
+            getattr(ddt_mytest, 'second_test_3'), '__doc__'),
+        None
     )
 
 
@@ -282,10 +307,6 @@ def test_ddt_data_unicode():
     """
     Test that unicode strings are converted to function names correctly
     """
-
-    def hello():
-        pass
-
     # We test unicode support separately for python 2 and 3
 
     if six.PY2:

pip install -e .
parse_log_pytest
requirements.txt
pytest
3.5
requirements/test.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
charset-normalizer==2.0.12
codecov==2.1.13
coverage==6.2
-e git+https://github.com/datadriventests/ddt.git@5e226e993a49de23f04ea9a281ca3960b731cf18#egg=ddt
flake8==5.0.4
idna==3.10
importlib-metadata==4.2.0
iniconfig==1.1.1
mccabe==0.7.0
mock==5.2.0
nose==1.3.7
packaging==21.3
pluggy==1.0.0
py==1.11.0
pycodestyle==2.9.1
pyflakes==2.5.0
pyparsing==3.1.4
pytest==7.0.1
PyYAML==6.0.1
requests==2.27.1
six==1.17.0
tomli==1.2.3
typing_extensions==4.1.1
urllib3==1.26.20
zipp==3.6.0

name: ddt
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - codecov==2.1.13
      - coverage==6.2
      - flake8==5.0.4
      - idna==3.10
      - importlib-metadata==4.2.0
      - iniconfig==1.1.1
      - mccabe==0.7.0
      - mock==5.2.0
      - nose==1.3.7
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pycodestyle==2.9.1
      - pyflakes==2.5.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pyyaml==6.0.1
      - requests==2.27.1
      - six==1.17.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - zipp==3.6.0
prefix: /opt/conda/envs/ddt

test/test_functional.py::test_ddt_data_doc_attribute
test/test_functional.py::test_data_decorator test/test_functional.py::test_file_data_decorator_with_dict test/test_functional.py::test_ddt test/test_functional.py::test_file_data_test_creation test/test_functional.py::test_file_data_test_names_dict test/test_functional.py::test_feed_data_data test/test_functional.py::test_feed_data_file_data test/test_functional.py::test_feed_data_file_data_missing_json test/test_functional.py::test_feed_data_file_data_missing_yaml test/test_functional.py::test_ddt_data_name_attribute test/test_functional.py::test_ddt_data_unicode test/test_functional.py::test_ddt_data_object test/test_functional.py::test_feed_data_with_invalid_identifier test/test_functional.py::test_load_yaml_without_yaml_support
.gitignore .travis.yml ddt.py tox.ini
.gitignore .travis.yml ddt.py tox.ini