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