Christian Heimes added the comment:

Pfff! I've written my best code after having one or two beers :)

Updates:
* Added class BytesWarning(Warning)
* Added -b/-bb command line args and Py_BytesWarningFlag
* issue PyErr_WarnEx(PyExc_BytesWarning) when Py_BytesWarningFlag is set.
* Added warning filter for BytesWarning that raises an exception if
Py_BytesWarningFlag > 1

Open questions:
* the warning filter isn't set when the initializer cannot load the
warning module (e.g. frozen apps). W/o the warning module Python is
screwed anyway and frozen apps would never add the -b argument.
* the warnings are only enabled with -b. They can't be enabled by
modifying the warnings.filters. Is this fine with you?

Added file: 
http://bugs.python.org/file8701/py3k-pep3137_str_bytes_warning2.patch

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1392>
__________________________________
Index: Python/pythonrun.c
===================================================================
--- Python/pythonrun.c	(Revision 58873)
+++ Python/pythonrun.c	(Arbeitskopie)
@@ -75,6 +75,7 @@
 int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */
 int Py_InspectFlag; /* Needed to determine whether to exit at SystemError */
 int Py_NoSiteFlag; /* Suppress 'import site' */
+int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */
 int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */
 int Py_FrozenFlag; /* Needed by getpath.c */
 int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */
@@ -262,9 +263,29 @@
 #endif /* WITH_THREAD */
 
 	warnings_module = PyImport_ImportModule("warnings");
-	if (!warnings_module)
+	if (!warnings_module) {
 		PyErr_Clear();
+	}
+	else {
+		PyObject *o;
+		char *action[8];
 
+		if (Py_BytesWarningFlag > 1)
+			*action = "error";
+		else if (Py_BytesWarningFlag)
+			*action = "default";
+		else
+			*action = "ignore";
+
+		o = PyObject_CallMethod(warnings_module,
+					"simplefilter", "sO",
+					*action, PyExc_BytesWarning);
+		if (o == NULL)
+			Py_FatalError("Py_Initialize: can't initialize"
+				      "warning filter for BytesWarning.");
+		Py_DECREF(o);
+        }
+
 #if defined(HAVE_LANGINFO_H) && defined(CODESET)
 	/* On Unix, set the file system encoding according to the
 	   user's preference, if the CODESET names a well-known
Index: Include/pydebug.h
===================================================================
--- Include/pydebug.h	(Revision 58873)
+++ Include/pydebug.h	(Arbeitskopie)
@@ -11,6 +11,7 @@
 PyAPI_DATA(int) Py_InspectFlag;
 PyAPI_DATA(int) Py_OptimizeFlag;
 PyAPI_DATA(int) Py_NoSiteFlag;
+PyAPI_DATA(int) Py_BytesWarningFlag;
 PyAPI_DATA(int) Py_UseClassExceptionsFlag;
 PyAPI_DATA(int) Py_FrozenFlag;
 PyAPI_DATA(int) Py_TabcheckFlag;
Index: Include/pyerrors.h
===================================================================
--- Include/pyerrors.h	(Revision 58873)
+++ Include/pyerrors.h	(Arbeitskopie)
@@ -165,6 +165,7 @@
 PyAPI_DATA(PyObject *) PyExc_FutureWarning;
 PyAPI_DATA(PyObject *) PyExc_ImportWarning;
 PyAPI_DATA(PyObject *) PyExc_UnicodeWarning;
+PyAPI_DATA(PyObject *) PyExc_BytesWarning;
 
 
 /* Convenience functions */
Index: Objects/bytesobject.c
===================================================================
--- Objects/bytesobject.c	(Revision 58873)
+++ Objects/bytesobject.c	(Arbeitskopie)
@@ -917,6 +917,17 @@
 }
 
 static PyObject *
+bytes_str(PyObject *op)
+{
+	if (Py_BytesWarningFlag) {
+		if (PyErr_WarnEx(PyExc_BytesWarning,
+				 "str() on a buffer instance", 1))
+			return NULL;
+	}
+	return bytes_repr((PyBytesObject*)op);
+}
+
+static PyObject *
 bytes_richcompare(PyObject *self, PyObject *other, int op)
 {
     Py_ssize_t self_size, other_size;
@@ -930,6 +941,12 @@
        error, even if the comparison is for equality. */
     if (PyObject_IsInstance(self, (PyObject*)&PyUnicode_Type) ||
         PyObject_IsInstance(other, (PyObject*)&PyUnicode_Type)) {
+        if (Py_BytesWarningFlag && op == Py_EQ) {
+            if (PyErr_WarnEx(PyExc_BytesWarning,
+                            "Comparsion between buffer and string", 1))
+                return NULL;
+        }
+
         Py_INCREF(Py_NotImplemented);
         return Py_NotImplemented;
     }
@@ -3082,7 +3099,7 @@
     &bytes_as_mapping,                  /* tp_as_mapping */
     0,                                  /* tp_hash */
     0,                                  /* tp_call */
-    (reprfunc)bytes_repr,               /* tp_str */
+    bytes_str,                          /* tp_str */
     PyObject_GenericGetAttr,            /* tp_getattro */
     0,                                  /* tp_setattro */
     &bytes_as_buffer,                   /* tp_as_buffer */
Index: Objects/exceptions.c
===================================================================
--- Objects/exceptions.c	(Revision 58873)
+++ Objects/exceptions.c	(Arbeitskopie)
@@ -1740,7 +1740,15 @@
     "Base class for warnings about Unicode related problems, mostly\n"
     "related to conversion problems.");
 
+/*
+ *    BytesWarning extends Warning
+ */
+SimpleExtendsException(PyExc_Warning, BytesWarning,
+    "Base class for warnings about bytes and buffer related problems, mostly\n"
+    "related to conversion from str or comparing to str.");
 
+
+
 /* Pre-computed MemoryError instance.  Best to create this as early as
  * possible and not wait until a MemoryError is actually raised!
  */
@@ -1839,6 +1847,7 @@
     PRE_INIT(FutureWarning)
     PRE_INIT(ImportWarning)
     PRE_INIT(UnicodeWarning)
+    PRE_INIT(BytesWarning)
 
     bltinmod = PyImport_ImportModule("__builtin__");
     if (bltinmod == NULL)
@@ -1899,6 +1908,7 @@
     POST_INIT(FutureWarning)
     POST_INIT(ImportWarning)
     POST_INIT(UnicodeWarning)
+    POST_INIT(BytesWarning)
 
     PyExc_MemoryErrorInst = BaseException_new(&_PyExc_MemoryError, NULL, NULL);
     if (!PyExc_MemoryErrorInst)
Index: Objects/stringobject.c
===================================================================
--- Objects/stringobject.c	(Revision 58873)
+++ Objects/stringobject.c	(Arbeitskopie)
@@ -679,6 +679,17 @@
 	return PyString_Repr(op, 1);
 }
 
+static PyObject *
+string_str(PyObject *op)
+{
+	if (Py_BytesWarningFlag) {
+		if (PyErr_WarnEx(PyExc_BytesWarning,
+				 "str() on a bytes instance", 1))
+			return NULL;
+	}
+	return string_repr(op);
+}
+
 static Py_ssize_t
 string_length(PyStringObject *a)
 {
@@ -830,6 +841,15 @@
 
 	/* Make sure both arguments are strings. */
 	if (!(PyString_Check(a) && PyString_Check(b))) {
+		if (Py_BytesWarningFlag && (op == Py_EQ) &&
+		    (PyObject_IsInstance((PyObject*)a,
+					 (PyObject*)&PyUnicode_Type) ||
+		    PyObject_IsInstance((PyObject*)b,
+					 (PyObject*)&PyUnicode_Type))) {
+			if (PyErr_WarnEx(PyExc_BytesWarning,
+				    "Comparsion between bytes and string", 1))
+				return NULL;
+		}
 		result = Py_NotImplemented;
 		goto out;
 	}
@@ -3074,13 +3094,13 @@
 	0,					/* tp_getattr */
 	0,					/* tp_setattr */
 	0,					/* tp_compare */
-	string_repr, 				/* tp_repr */
+	(reprfunc)string_repr, 			/* tp_repr */
 	0,					/* tp_as_number */
 	&string_as_sequence,			/* tp_as_sequence */
 	&string_as_mapping,			/* tp_as_mapping */
 	(hashfunc)string_hash, 			/* tp_hash */
 	0,					/* tp_call */
-	string_repr,				/* tp_str */
+	string_str,				/* tp_str */
 	PyObject_GenericGetAttr,		/* tp_getattro */
 	0,					/* tp_setattro */
 	&string_as_buffer,			/* tp_as_buffer */
Index: Misc/NEWS
===================================================================
--- Misc/NEWS	(Revision 58873)
+++ Misc/NEWS	(Arbeitskopie)
@@ -31,6 +31,9 @@
 - io.open() and _fileio.FileIO have grown a new argument closefd. A false
   value disables the closing of the file descriptor.
 
+- Added a new option -b to issues warnings (-bb for errors) about certain
+  operations between bytes/buffer and str like str(b'') and comparsion.
+
 Extension Modules
 -----------------
 
Index: Doc/library/warnings.rst
===================================================================
--- Doc/library/warnings.rst	(Revision 58873)
+++ Doc/library/warnings.rst	(Arbeitskopie)
@@ -80,7 +80,11 @@
 | :exc:`UnicodeWarning`            | Base category for warnings related to         |
 |                                  | Unicode.                                      |
 +----------------------------------+-----------------------------------------------+
+| :exc:`BytesWarning`              | Base category for warnings related to         |
+|                                  | bytes and buffer.                             |
++----------------------------------+-----------------------------------------------+
 
+
 While these are technically built-in exceptions, they are documented here,
 because conceptually they belong to the warnings mechanism.
 
Index: Doc/library/exceptions.rst
===================================================================
--- Doc/library/exceptions.rst	(Revision 58873)
+++ Doc/library/exceptions.rst	(Arbeitskopie)
@@ -405,6 +405,10 @@
 
    Base class for warnings related to Unicode.
 
+.. exception:: BytesWarning
+
+   Base class for warnings related to bytes and buffer.
+
 The class hierarchy for built-in exceptions is:
 
 
Index: Lib/test/test_bytes.py
===================================================================
--- Lib/test/test_bytes.py	(Revision 58873)
+++ Lib/test/test_bytes.py	(Arbeitskopie)
@@ -12,6 +12,7 @@
 import pickle
 import tempfile
 import unittest
+import warnings
 import test.test_support
 import test.string_tests
 import test.buffer_tests
@@ -19,6 +20,12 @@
 
 class BytesTest(unittest.TestCase):
 
+    def setUp(self):
+        self.warning_filters = warnings.filters[:]
+
+    def tearDown(self):
+        warnings.filters = self.warning_filters
+
     def test_basics(self):
         b = buffer()
         self.assertEqual(type(b), buffer)
@@ -87,6 +94,7 @@
         self.assertRaises(ValueError, buffer, [10**100])
 
     def test_repr_str(self):
+        warnings.simplefilter('ignore', BytesWarning)
         for f in str, repr:
             self.assertEqual(f(buffer()), "buffer(b'')")
             self.assertEqual(f(buffer([0])), "buffer(b'\\x00')")
@@ -149,6 +157,8 @@
         self.assertEqual(bytes(b"abc") < b"ab", False)
         self.assertEqual(bytes(b"abc") <= b"ab", False)
 
+    def test_compare_to_str(self):
+        warnings.simplefilter('ignore', BytesWarning)
         # Byte comparisons with unicode should always fail!
         # Test this for all expected byte orders and Unicode character sizes
         self.assertEqual(b"\0a\0b\0c" == "abc", False)
@@ -371,6 +381,7 @@
         self.assertEqual(b, buffer(sample))
 
     def test_to_str(self):
+        warnings.simplefilter('ignore', BytesWarning)
         self.assertEqual(str(b''), "b''")
         self.assertEqual(str(b'x'), "b'x'")
         self.assertEqual(str(b'\x80'), "b'\\x80'")
Index: Lib/test/exception_hierarchy.txt
===================================================================
--- Lib/test/exception_hierarchy.txt	(Revision 58873)
+++ Lib/test/exception_hierarchy.txt	(Arbeitskopie)
@@ -44,5 +44,6 @@
            +-- SyntaxWarning
            +-- UserWarning
            +-- FutureWarning
-	   +-- ImportWarning
-	   +-- UnicodeWarning
+           +-- ImportWarning
+           +-- UnicodeWarning
+           +-- BytesWarning
Index: Modules/main.c
===================================================================
--- Modules/main.c	(Revision 58873)
+++ Modules/main.c	(Arbeitskopie)
@@ -44,7 +44,7 @@
 static int  orig_argc;
 
 /* command line options */
-#define BASE_OPTS "c:dEhim:OStuvVW:xX?"
+#define BASE_OPTS "bc:dEhim:OStuvVW:xX?"
 
 #define PROGRAM_OPTS BASE_OPTS
 
@@ -55,32 +55,34 @@
 /* Long usage message, split into parts < 512 bytes */
 static char *usage_1 = "\
 Options and arguments (and corresponding environment variables):\n\
+-b     : issue warnings about str(bytes_instance), str(buffer_instance)\n\
+         and comparing bytes/buffer with str. (-bb: issue errors)\n\
 -c cmd : program passed in as string (terminates option list)\n\
 -d     : debug output from parser; also PYTHONDEBUG=x\n\
 -E     : ignore environment variables (such as PYTHONPATH)\n\
 -h     : print this help message and exit (also --help)\n\
+";
+static char *usage_2 = "\
 -i     : inspect interactively after running script; forces a prompt even\n\
          if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n\
-";
-static char *usage_2 = "\
 -m mod : run library module as a script (terminates option list)\n\
 -O     : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x\n\
 -OO    : remove doc-strings in addition to the -O optimizations\n\
 -S     : don't imply 'import site' on initialization\n\
 -t     : issue warnings about inconsistent tab usage (-tt: issue errors)\n\
--u     : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x\n\
 ";
 static char *usage_3 = "\
+-u     : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x\n\
          see man page for details on internal buffering relating to '-u'\n\
 -v     : verbose (trace import statements); also PYTHONVERBOSE=x\n\
          can be supplied multiple times to increase verbosity\n\
 -V     : print the Python version number and exit (also --version)\n\
 -W arg : warning control; arg is action:message:category:module:lineno\n\
 -x     : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
+";
+static char *usage_4 = "\
 file   : program read from script file\n\
 -      : program read from stdin (default; interactive mode if a tty)\n\
-";
-static char *usage_4 = "\
 arg ...: arguments passed to program in sys.argv[1:]\n\n\
 Other environment variables:\n\
 PYTHONSTARTUP: file executed on interactive startup (no default)\n\
@@ -252,6 +254,9 @@
 		}
 
 		switch (c) {
+		case 'b':
+			Py_BytesWarningFlag++;
+			break;
 
 		case 'd':
 			Py_DebugFlag++;
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to