Fix #134 - wrap str, bytes, and any non-iterable input
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index ea8d4da..8196da0 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -10,6 +10,9 @@
       (https://github.com/wolever/parameterized/pull/135; thanks @Ronserruya)
     * Work around for bug bpo-40126 in older versions of ``mock``
       (https://github.com/wolever/parameterized/pull/129; thanks @alexpizarroj)
+    * Allow str, bytes, and any non-iterable input to be passed to
+      ``@parameterized`` without wrapping in a tuple
+      (https://github.com/wolever/parameterized/pull/157)
 
 0.8.1 (2021-01-09)
     * Add README and LICENSE to pypi sdist package
diff --git a/parameterized/parameterized.py b/parameterized/parameterized.py
index b68ec21..d94be9b 100644
--- a/parameterized/parameterized.py
+++ b/parameterized/parameterized.py
@@ -2,6 +2,7 @@
 import sys
 import inspect
 import warnings
+from typing import Iterable
 from functools import wraps
 from types import MethodType as MethodType
 from collections import namedtuple
@@ -208,7 +209,7 @@
             """
         if isinstance(args, param):
             return args
-        elif isinstance(args, string_types):
+        elif isinstance(args, (str, bytes)) or not isinstance(args, Iterable):
             args = (args, )
         try:
             return cls(*args)
@@ -635,6 +636,8 @@
 
     @classmethod
     def to_safe_name(cls, s):
+        if not isinstance(s, str):
+            s = str(s)
         return str(re.sub("[^a-zA-Z0-9_]+", "_", s))
 
 
diff --git a/parameterized/test.py b/parameterized/test.py
index 8f28d7a..1d012ad 100644
--- a/parameterized/test.py
+++ b/parameterized/test.py
@@ -93,15 +93,19 @@
 test_params = [
     (42, ),
     "foo0",
+    b"bar",
+    123,
     param("foo1"),
     param("foo2", bar=42),
 ]
 
 expect("standalone", [
+    "test_naked_function(42, bar=None)",
     "test_naked_function('foo0', bar=None)",
+    "test_naked_function(b'bar', bar=None)",
+    "test_naked_function(123, bar=None)",
     "test_naked_function('foo1', bar=None)",
     "test_naked_function('foo2', bar=42)",
-    "test_naked_function(42, bar=None)",
 ])
 
 @parameterized(test_params)
@@ -111,10 +115,12 @@
 
 class TestParameterized(object):
     expect("generator", [
+        "test_instance_method(42, bar=None)",
+        "test_instance_method(b'bar', bar=None)",
+        "test_instance_method(123, bar=None)",
         "test_instance_method('foo0', bar=None)",
         "test_instance_method('foo1', bar=None)",
         "test_instance_method('foo2', bar=42)",
-        "test_instance_method(42, bar=None)",
     ])
 
     @parameterized(test_params)
@@ -149,7 +155,8 @@
 
 def custom_naming_func(custom_tag):
     def custom_naming_func(testcase_func, param_num, param):
-        return testcase_func.__name__ + ('_%s_name_' % custom_tag) + str(param.args[0])
+        arg = param.args[0]
+        return testcase_func.__name__ + ('_%s_name_' % custom_tag) + parameterized.to_safe_name(arg)
 
     return custom_naming_func
 
@@ -287,10 +294,12 @@
 
 class TestParamerizedOnTestCase(TestCase):
     expect([
+        "test_on_TestCase(42, bar=None)",
+        "test_on_TestCase(b'bar', bar=None)",
+        "test_on_TestCase(123, bar=None)",
         "test_on_TestCase('foo0', bar=None)",
         "test_on_TestCase('foo1', bar=None)",
         "test_on_TestCase('foo2', bar=42)",
-        "test_on_TestCase(42, bar=None)",
     ])
 
     @parameterized.expand(test_params)
@@ -299,6 +308,8 @@
 
     expect([
         "test_on_TestCase2_custom_name_42(42, bar=None)",
+        "test_on_TestCase2_custom_name_b_bar_(b'bar', bar=None)",
+        "test_on_TestCase2_custom_name_123(123, bar=None)",
         "test_on_TestCase2_custom_name_foo0('foo0', bar=None)",
         "test_on_TestCase2_custom_name_foo1('foo1', bar=None)",
         "test_on_TestCase2_custom_name_foo2('foo2', bar=42)",
@@ -311,7 +322,7 @@
         frame = stack[1]
         frame_locals = frame[0].f_locals
         nose_test_method_name = frame_locals['a'][0]._testMethodName
-        expected_name = "test_on_TestCase2_custom_name_" + str(foo)
+        expected_name = "test_on_TestCase2_custom_name_" + parameterized.to_safe_name(foo)
         assert_equal(nose_test_method_name, expected_name,
                      "Test Method name '%s' did not get customized to expected: '%s'" %
                      (nose_test_method_name, expected_name))
@@ -393,14 +404,6 @@
     else:
         raise AssertionError("Expected exception not raised")
 
-def test_helpful_error_on_invalid_parameters():
-    try:
-        parameterized([1432141234243])(lambda: None)
-    except Exception as e:
-        assert_contains(str(e), "Parameters must be tuples")
-    else:
-        raise AssertionError("Expected exception not raised")
-
 
 def test_helpful_error_on_empty_iterable_input():
     try: