Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5988617

Browse filesBrowse files
committed
Warning propagation improvements
- Include error code in warnings, not just string - Fix warning propagation for unbuffered queries
1 parent dadd392 commit 5988617
Copy full SHA for 5988617

File tree

Expand file treeCollapse file tree

3 files changed

+50
-7
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+50
-7
lines changed

‎pymysql/cursors.py

Copy file name to clipboardExpand all lines: pymysql/cursors.py
+20-6Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class Cursor(object):
3030
#: Default value of max_allowed_packet is 1048576.
3131
max_stmt_length = 1024000
3232

33+
_defer_warnings = False
34+
3335
def __init__(self, connection):
3436
'''
3537
Do not create an instance of a Cursor yourself. Call
@@ -43,6 +45,7 @@ def __init__(self, connection):
4345
self._executed = None
4446
self._result = None
4547
self._rows = None
48+
self._warnings_handled = False
4649

4750
def close(self):
4851
'''
@@ -86,6 +89,9 @@ def _nextset(self, unbuffered=False):
8689
"""Get the next query set"""
8790
conn = self._get_db()
8891
current_result = self._result
92+
# for unbuffered queries warnings are only available once whole result has been read
93+
if unbuffered:
94+
self._show_warnings()
8995
if current_result is None or current_result is not conn._result:
9096
return None
9197
if not current_result.has_next:
@@ -328,22 +334,26 @@ def _do_get_result(self):
328334
self.description = result.description
329335
self.lastrowid = result.insert_id
330336
self._rows = result.rows
337+
self._warnings_handled = False
331338

332-
if result.warning_count > 0:
333-
self._show_warnings(conn)
339+
if not self._defer_warnings:
340+
self._show_warnings()
334341

335-
def _show_warnings(self, conn):
336-
if self._result and self._result.has_next:
342+
def _show_warnings(self):
343+
if self._warnings_handled:
344+
return
345+
self._warnings_handled = True
346+
if self._result and (self._result.has_next or not self._result.warning_count):
337347
return
338-
ws = conn.show_warnings()
348+
ws = self._get_db().show_warnings()
339349
if ws is None:
340350
return
341351
for w in ws:
342352
msg = w[-1]
343353
if PY2:
344354
if isinstance(msg, unicode):
345355
msg = msg.encode('utf-8', 'replace')
346-
warnings.warn(str(msg), err.Warning, 4)
356+
warnings.warn(err.Warning(*w[1:3]), stacklevel=4)
347357

348358
def __iter__(self):
349359
return iter(self.fetchone, None)
@@ -404,6 +414,8 @@ class SSCursor(Cursor):
404414
possible to scroll backwards, as only the current row is held in memory.
405415
"""
406416

417+
_defer_warnings = True
418+
407419
def _conv_row(self, row):
408420
return row
409421

@@ -440,6 +452,7 @@ def fetchone(self):
440452
self._check_executed()
441453
row = self.read_next()
442454
if row is None:
455+
self._show_warnings()
443456
return None
444457
self.rownumber += 1
445458
return row
@@ -473,6 +486,7 @@ def fetchmany(self, size=None):
473486
for i in range_type(size):
474487
row = self.read_next()
475488
if row is None:
489+
self._show_warnings()
476490
break
477491
rows.append(row)
478492
self.rownumber += 1

‎pymysql/tests/test_DictCursor.py

Copy file name to clipboardExpand all lines: pymysql/tests/test_DictCursor.py
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ def setUp(self):
2121
with warnings.catch_warnings():
2222
warnings.filterwarnings("ignore")
2323
c.execute("drop table if exists dictcursor")
24-
c.execute("""CREATE TABLE dictcursor (name char(20), age int , DOB datetime)""")
24+
# include in filterwarnings since for unbuffered dict cursor warning for lack of table
25+
# will only be propagated at start of next execute() call
26+
c.execute("""CREATE TABLE dictcursor (name char(20), age int , DOB datetime)""")
2527
data = [("bob", 21, "1990-02-06 23:04:56"),
2628
("jim", 56, "1955-05-09 13:12:45"),
2729
("fred", 100, "1911-09-12 01:01:01")]

‎pymysql/tests/test_issues.py

Copy file name to clipboardExpand all lines: pymysql/tests/test_issues.py
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import sys
55

66
import pymysql
7+
from pymysql import cursors
8+
from pymysql._compat import text_type
79
from pymysql.tests import base
810
import unittest2
911

@@ -486,3 +488,28 @@ def test_issue_363(self):
486488
# don't assert the exact internal binary value, as it could
487489
# vary across implementations
488490
self.assertTrue(isinstance(row[0], bytes))
491+
492+
def test_issue_491(self):
493+
""" Test warning propagation """
494+
conn = pymysql.connect(charset="utf8", **self.databases[0])
495+
496+
with warnings.catch_warnings():
497+
# Ignore all warnings other than pymysql generated ones
498+
warnings.simplefilter("ignore")
499+
warnings.simplefilter("error", category=pymysql.Warning)
500+
501+
# verify for both buffered and unbuffered cursor types
502+
for cursor_class in (cursors.Cursor, cursors.SSCursor):
503+
c = conn.cursor(cursor_class)
504+
try:
505+
c.execute("SELECT CAST('124b' AS SIGNED)")
506+
c.fetchall()
507+
except pymysql.Warning as e:
508+
# Warnings should have errorcode and string message, just like exceptions
509+
self.assertEqual(len(e.args), 2)
510+
self.assertEqual(e.args[0], 1292)
511+
self.assertTrue(isinstance(e.args[1], text_type))
512+
else:
513+
self.fail("Should raise Warning")
514+
finally:
515+
c.close()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.