Skip to content

Commit b84b32b

Browse files
author
Ramiro Morales
committed
Add tests and docs.
1 parent c7e5220 commit b84b32b

File tree

3 files changed

+184
-2
lines changed

3 files changed

+184
-2
lines changed

docs/_mssql_examples.rst

+34-2
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ An example of exception handling
8787
8888
import _mssql
8989
90+
conn = _mssql.connect(server='SQL01', user='user', password='password',
91+
database='mydatabase')
9092
try:
91-
conn = _mssql.connect(server='SQL01', user='user', password='password',
92-
database='mydatabase')
9393
conn.execute_non_query('CREATE TABLE t1(id INT, name VARCHAR(50))')
9494
except _mssql.MssqlDatabaseException as e:
9595
if e.number == 2714 and e.severity == 16:
@@ -99,4 +99,36 @@ An example of exception handling
9999
finally:
100100
conn.close()
101101
102+
Custom message handlers
103+
=======================
104+
105+
You can provide your own message handler callback function that will be called
106+
by the stack with informative messages send by the server. Set it by `_mssql`
107+
connection by using the `set_msghandler` method:
108+
109+
.. code-block:: python
110+
111+
import _mssql
112+
113+
def my_msg_handler(msgstate, severity, srvname, procname, line, msgtext):
114+
"""
115+
Our custom handler -- It simpy prints a string to stdout assembled from
116+
the pieces of information sent by the server.
117+
"""
118+
print("my_msg_handler: msgstate = %d, severity = %d, procname = '%s', "
119+
"line = %d, msgtext = '%s'" % (msgstate, severity, procname,
120+
line, msgtext))
121+
122+
conn = _mssql.connect(server='SQL01', user='user', password='password')
123+
try:
124+
conn.set_msghandler(my_msg_handler) # Install our custom handler
125+
cnx.execute_non_query("USE mydatabase") # It gets called at this point
126+
finally:
127+
conn.close()
128+
129+
Something similar to this would be printed to the standard output::
130+
131+
my_msg_handler: msgstate = x, severity = y, procname = '', line = 1, msgtext = 'Changed database context to 'mydatabase'.'
132+
133+
102134
.. todo:: Add an example of invoking a Stored Procedure using ``_mssql``.

docs/ref/_mssql.rst

+14
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,20 @@ Functions
251251
These methods facilitate the Python iterator protocol. You most likely will not
252252
call them directly, but indirectly by using iterators.
253253

254+
.. method:: MSSQLConnection.set_msghandler(handler)
255+
256+
This method allows setting a message handler function for the connection to
257+
allow a client to gain access to the messages returned from the server.
258+
259+
The signature of the message handler function *handler* passed to this
260+
method must be::
261+
262+
def my_msg_handler(msgstate, severity, srvname, procname, line, msgtext):
263+
# The body of the message handler.
264+
265+
*msgstate*, *severity* and *line* will be integers, *srvname*, *procname* and
266+
*msgtext* will be strings.
267+
254268
``MSSQLStoredProcedure`` class
255269
==============================
256270

tests/test_user_msghandler.py

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
try:
2+
import unittest2 as unittest
3+
except ImportError:
4+
import unittest
5+
6+
from .helpers import config, mssqlconn
7+
8+
msgs = []
9+
10+
11+
def user_msg_handler1(msgstate, severity, srvname, procname, line, msgtext):
12+
global msgs
13+
entry = ("msg_handler1: msgstate = %d, severity = %d, procname = '%s', "
14+
"line = %d, msgtext = '%s'") % (msgstate, severity, procname, line, msgtext)
15+
msgs.append(entry)
16+
17+
18+
def user_msg_handler2(msgstate, severity, srvname, procname, line, msgtext):
19+
global msgs
20+
entry = ("msg_handler2: msgstate = %d, severity = %d, procname = '%s', "
21+
"line = %d, msgtext = '%s'") % (msgstate, severity, procname, line, msgtext)
22+
msgs.append(entry)
23+
24+
25+
def wrong_signature_msg_handler():
26+
pass
27+
28+
29+
class TestUserMsgHandler(unittest.TestCase):
30+
31+
def test_basic_functionality(self):
32+
cnx = mssqlconn()
33+
try:
34+
cnx.set_msghandler(user_msg_handler1)
35+
msgs_before = len(msgs)
36+
cnx.execute_non_query("USE master")
37+
msgs_after = len(msgs)
38+
delta = msgs_after - msgs_before
39+
self.assertEqual(delta, 1)
40+
expect = ("msg_handler1: msgstate = 1, severity = 0, procname = ''"
41+
", line = 1, msgtext = 'Changed database context to 'master'.'")
42+
self.assertEqual(expect, msgs[msgs_after - 1])
43+
finally:
44+
cnx.close()
45+
46+
def test_set_handler_to_none(self):
47+
cnx = mssqlconn()
48+
try:
49+
cnx.set_msghandler(None)
50+
msgs_before = len(msgs)
51+
cnx.execute_non_query("USE master")
52+
msgs_after = len(msgs)
53+
delta = msgs_after - msgs_before
54+
self.assertEqual(delta, 0)
55+
finally:
56+
cnx.close()
57+
58+
def test_change_handler(self):
59+
cnx = mssqlconn()
60+
try:
61+
cnx.set_msghandler(user_msg_handler1)
62+
msgs_before = len(msgs)
63+
cnx.execute_non_query("USE master")
64+
msgs_after = len(msgs)
65+
delta = msgs_after - msgs_before
66+
self.assertEqual(delta, 1)
67+
expect = ("msg_handler1: msgstate = 1, severity = 0, procname = ''"
68+
", line = 1, msgtext = 'Changed database context to 'master'.'")
69+
self.assertEqual(expect, msgs[msgs_after - 1])
70+
71+
cnx.set_msghandler(user_msg_handler2)
72+
msgs_before = len(msgs)
73+
cnx.execute_non_query("USE %s" % config.database)
74+
msgs_after = len(msgs)
75+
delta = msgs_after - msgs_before
76+
self.assertEqual(delta, 1)
77+
expect = ("msg_handler2: msgstate = 1, severity = 0, procname = ''"
78+
", line = 1, msgtext = 'Changed database context to '%s'.'") % config.database
79+
self.assertEqual(expect, msgs[msgs_after - 1])
80+
finally:
81+
cnx.close()
82+
83+
def test_per_conn_handlers(self):
84+
cnx1 = mssqlconn()
85+
cnx2 = mssqlconn()
86+
try:
87+
cnx1.set_msghandler(user_msg_handler1)
88+
msgs_before = len(msgs)
89+
cnx1.execute_non_query("USE master")
90+
msgs_after = len(msgs)
91+
delta = msgs_after - msgs_before
92+
self.assertEqual(delta, 1)
93+
expect = ("msg_handler1: msgstate = 1, severity = 0, procname = ''"
94+
", line = 1, msgtext = 'Changed database context to 'master'.'")
95+
self.assertEqual(expect, msgs[msgs_after - 1])
96+
97+
cnx2.set_msghandler(user_msg_handler2)
98+
msgs_before = len(msgs)
99+
cnx2.execute_non_query("USE %s" % config.database)
100+
msgs_after = len(msgs)
101+
delta = msgs_after - msgs_before
102+
self.assertEqual(delta, 1)
103+
expect = ("msg_handler2: msgstate = 1, severity = 0, procname = ''"
104+
", line = 1, msgtext = 'Changed database context to '%s'.'") % config.database
105+
self.assertEqual(expect, msgs[msgs_after - 1])
106+
finally:
107+
cnx1.close()
108+
cnx2.close()
109+
110+
@staticmethod
111+
def user_msg_handler3(msgstate, severity, srvname, procname, line, msgtext):
112+
global msgs
113+
entry = ("msg_handler3 called")
114+
msgs.append(entry)
115+
116+
def test_static_method_handler(self):
117+
cnx = mssqlconn()
118+
try:
119+
cnx.set_msghandler(self.user_msg_handler3)
120+
msgs_before = len(msgs)
121+
cnx.execute_non_query("USE master")
122+
msgs_after = len(msgs)
123+
delta = msgs_after - msgs_before
124+
self.assertEqual(delta, 1)
125+
expect = ("msg_handler3 called")
126+
self.assertEqual(expect, msgs[msgs_after - 1])
127+
finally:
128+
cnx.close()
129+
130+
def test_wrong_signature_handler(self):
131+
cnx = mssqlconn()
132+
try:
133+
cnx.set_msghandler(wrong_signature_msg_handler)
134+
cnx.execute_non_query("USE master")
135+
finally:
136+
cnx.close()

0 commit comments

Comments
 (0)