From eea3a91b43f1ac9698347db2ac3aa87740345494 Mon Sep 17 00:00:00 2001 From: Julius Park Date: Tue, 30 Jun 2020 14:24:58 -0400 Subject: [PATCH 01/10] fix NotMasterError issue --- pymongo/errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymongo/errors.py b/pymongo/errors.py index cf32546850..b9281e742a 100644 --- a/pymongo/errors.py +++ b/pymongo/errors.py @@ -114,7 +114,7 @@ class NotMasterError(AutoReconnect): Subclass of :exc:`~pymongo.errors.AutoReconnect`. """ def __str__(self): - output_str = "%s, full error: %s" % (self._message, self.__details) + output_str = "%s, full error: %s" % (self._message, self.details) if sys.version_info[0] == 2 and isinstance(output_str, unicode): return output_str.encode('utf-8', errors='replace') return output_str From 7b4121859ab0157967926378582493077a1316bf Mon Sep 17 00:00:00 2001 From: Julius Park Date: Tue, 30 Jun 2020 16:27:09 -0400 Subject: [PATCH 02/10] Added tests --- test/test_monitoring.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_monitoring.py b/test/test_monitoring.py index ede08c011d..81437a47fd 100644 --- a/test/test_monitoring.py +++ b/test/test_monitoring.py @@ -439,6 +439,9 @@ def test_not_master_error(self): client.pymongo_test.test.find_one_and_delete({}) except NotMasterError as exc: error = exc.errors + import traceback + self.assertIn("full error", str(exc)) + self.assertIn("full error", traceback.format_exc()) results = self.listener.results started = results['started'][0] failed = results['failed'][0] From 269d554fbc618a8bd58f05d619f9ef89dcbab4d8 Mon Sep 17 00:00:00 2001 From: Julius Park Date: Wed, 1 Jul 2020 09:38:29 -0400 Subject: [PATCH 03/10] moved test case to another file --- test/test_errors.py | 23 +++++++++++++++++++++++ test/test_monitoring.py | 3 --- 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 test/test_errors.py diff --git a/test/test_errors.py b/test/test_errors.py new file mode 100644 index 0000000000..005abd9d47 --- /dev/null +++ b/test/test_errors.py @@ -0,0 +1,23 @@ +from pymongo.errors import (AutoReconnect, + NotMasterError, + OperationFailure) +from test import (client_context, + client_knobs, + PyMongoTestCase, + sanitize_cmd, + unittest) +from test.utils import (EventListener, + get_pool, + rs_or_single_client, + single_client, + wait_until) + +class TestCommandMonitoring(PyMongoTestCase): + def test_not_master_error(self): + exc = NotMasterError("not master test", "details") + self.assertIn("full error", str(exc)) + try: + raise exc + except NotMasterError: + import traceback + self.assertIn("full error", traceback.format_exc()) \ No newline at end of file diff --git a/test/test_monitoring.py b/test/test_monitoring.py index 81437a47fd..ede08c011d 100644 --- a/test/test_monitoring.py +++ b/test/test_monitoring.py @@ -439,9 +439,6 @@ def test_not_master_error(self): client.pymongo_test.test.find_one_and_delete({}) except NotMasterError as exc: error = exc.errors - import traceback - self.assertIn("full error", str(exc)) - self.assertIn("full error", traceback.format_exc()) results = self.listener.results started = results['started'][0] failed = results['failed'][0] From 82edc07042c2c8c34730fa73a66879f05bf3ce55 Mon Sep 17 00:00:00 2001 From: Julius Park Date: Wed, 1 Jul 2020 11:00:22 -0400 Subject: [PATCH 04/10] cleaned up test case --- test/test_errors.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/test_errors.py b/test/test_errors.py index 005abd9d47..2be74e206a 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -6,13 +6,8 @@ PyMongoTestCase, sanitize_cmd, unittest) -from test.utils import (EventListener, - get_pool, - rs_or_single_client, - single_client, - wait_until) -class TestCommandMonitoring(PyMongoTestCase): +class TestErrors(PyMongoTestCase): def test_not_master_error(self): exc = NotMasterError("not master test", "details") self.assertIn("full error", str(exc)) @@ -20,4 +15,4 @@ def test_not_master_error(self): raise exc except NotMasterError: import traceback - self.assertIn("full error", traceback.format_exc()) \ No newline at end of file + self.assertIn("full error", traceback.format_exc()) From 8a90deef7c8bbd2d64e8f7f1e1b24d284bbf059e Mon Sep 17 00:00:00 2001 From: Julius Park Date: Thu, 2 Jul 2020 09:50:40 -0400 Subject: [PATCH 05/10] added test for operation failure --- test/test_errors.py | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/test/test_errors.py b/test/test_errors.py index 2be74e206a..ed292b31cf 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -1,18 +1,42 @@ -from pymongo.errors import (AutoReconnect, - NotMasterError, +# Copyright 2019-present MongoDB, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import sys +import traceback +sys.path[0:0] = [""] +from pymongo.errors import (NotMasterError, OperationFailure) -from test import (client_context, - client_knobs, - PyMongoTestCase, - sanitize_cmd, +from test import (PyMongoTestCase, unittest) + class TestErrors(PyMongoTestCase): def test_not_master_error(self): - exc = NotMasterError("not master test", "details") + exc = NotMasterError("not master test", {"ok": 0, "errmsg":"error"}) self.assertIn("full error", str(exc)) try: raise exc except NotMasterError: - import traceback self.assertIn("full error", traceback.format_exc()) + + def test_operation_failure(self): + exc = OperationFailure("operation failure test", {"ok": 0, "errmsg":"error"}) + self.assertIn("full error", str(exc)) + try: + raise exc + except OperationFailure: + self.assertIn("full error", traceback.format_exc()) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 7c5b7fbe4a4e7bb799d691454ed5a991411df44f Mon Sep 17 00:00:00 2001 From: Julius Park Date: Thu, 2 Jul 2020 12:57:47 -0400 Subject: [PATCH 06/10] added unicode testing --- pymongo/errors.py | 20 ++++++++++---------- test/test_errors.py | 28 +++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/pymongo/errors.py b/pymongo/errors.py index b9281e742a..df10661a2b 100644 --- a/pymongo/errors.py +++ b/pymongo/errors.py @@ -113,11 +113,13 @@ class NotMasterError(AutoReconnect): Subclass of :exc:`~pymongo.errors.AutoReconnect`. """ - def __str__(self): - output_str = "%s, full error: %s" % (self._message, self.details) - if sys.version_info[0] == 2 and isinstance(output_str, unicode): - return output_str.encode('utf-8', errors='replace') - return output_str + def __init__(self, message='', errors=None): + if errors is not None: + message = "%s, full error: %s" % (message, errors) + if sys.version_info[0] == 2 and isinstance(message, unicode): + message = message.encode('utf-8', errors='replace') + super(NotMasterError, self).__init__(message, errors=errors) + class ServerSelectionTimeoutError(AutoReconnect): """Thrown when no MongoDB server is available for an operation @@ -148,6 +150,9 @@ def __init__(self, error, code=None, details=None): error_labels = None if details is not None: error_labels = details.get('errorLabels') + error = "%s, full error: %s" % (error, details) + if sys.version_info[0] == 2 and isinstance(error, unicode): + error = error.encode('utf-8', errors='replace') super(OperationFailure, self).__init__( error, error_labels=error_labels) self.__code = code @@ -171,11 +176,6 @@ def details(self): """ return self.__details - def __str__(self): - output_str = "%s, full error: %s" % (self._message, self.__details) - if sys.version_info[0] == 2 and isinstance(output_str, unicode): - return output_str.encode('utf-8', errors='replace') - return output_str class CursorNotFound(OperationFailure): """Raised while iterating query results if the cursor is diff --git a/test/test_errors.py b/test/test_errors.py index ed292b31cf..2cb1a0a6b1 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -1,4 +1,4 @@ -# Copyright 2019-present MongoDB, Inc. +# Copyright 2020-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -11,9 +11,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + import sys import traceback + sys.path[0:0] = [""] + from pymongo.errors import (NotMasterError, OperationFailure) from test import (PyMongoTestCase, @@ -30,13 +33,32 @@ def test_not_master_error(self): self.assertIn("full error", traceback.format_exc()) def test_operation_failure(self): - exc = OperationFailure("operation failure test", {"ok": 0, "errmsg":"error"}) + exc = OperationFailure("operation failure test", 10, {"ok": 0, "errmsg":"error"}) self.assertIn("full error", str(exc)) try: raise exc except OperationFailure: self.assertIn("full error", traceback.format_exc()) + def _test_unicode_strs(self, exc): + if sys.version_info[0] == 2: + self.assertEqual("unicode \xf0\x9f\x90\x8d, full error: {'ok': 0, 'errmsg': u'unicode \\U0001f40d'}", str(exc)) + else: + self.assertEqual("unicode \U0001f40d, full error: {'ok': 0, 'errmsg': 'unicode \U0001f40d'}", str(exc)) + try: + raise exc + except Exception: + self.assertIn("full error", traceback.format_exc()) + + def test_unicode_strs_operation_failure(self): + exc = OperationFailure(u'unicode \U0001f40d', 10, {"ok": 0, "errmsg": u'unicode \U0001f40d'}) + self._test_unicode_strs(exc) + + def test_unicode_strs_not_master_error(self): + exc = NotMasterError(u'unicode \U0001f40d', {"ok": 0, "errmsg": u'unicode \U0001f40d'}) + self._test_unicode_strs(exc) + + if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From 4cfb959eb9b3ee6a89ce8ff63528aec37e7eb7a9 Mon Sep 17 00:00:00 2001 From: Julius Park Date: Thu, 2 Jul 2020 13:07:17 -0400 Subject: [PATCH 07/10] refactored, added helper methods --- .idea/codeStyles/codeStyleConfig.xml | 5 +++++ pymongo/errors.py | 20 +++++++++++--------- test/test_errors.py | 15 ++++++++++----- 3 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..a55e7a179b --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/pymongo/errors.py b/pymongo/errors.py index df10661a2b..973719dbd1 100644 --- a/pymongo/errors.py +++ b/pymongo/errors.py @@ -100,6 +100,14 @@ class NetworkTimeout(AutoReconnect): """ +def _format_detailed_error(message, details): + if details is not None: + message = "%s, full error: %s" % (message, details) + if sys.version_info[0] == 2 and isinstance(message, unicode): + message = message.encode('utf-8', errors='replace') + return message + + class NotMasterError(AutoReconnect): """The server responded "not master" or "node is recovering". @@ -114,11 +122,8 @@ class NotMasterError(AutoReconnect): Subclass of :exc:`~pymongo.errors.AutoReconnect`. """ def __init__(self, message='', errors=None): - if errors is not None: - message = "%s, full error: %s" % (message, errors) - if sys.version_info[0] == 2 and isinstance(message, unicode): - message = message.encode('utf-8', errors='replace') - super(NotMasterError, self).__init__(message, errors=errors) + super(NotMasterError, self).__init__( + _format_detailed_error(message, errors), errors=errors) class ServerSelectionTimeoutError(AutoReconnect): @@ -150,11 +155,8 @@ def __init__(self, error, code=None, details=None): error_labels = None if details is not None: error_labels = details.get('errorLabels') - error = "%s, full error: %s" % (error, details) - if sys.version_info[0] == 2 and isinstance(error, unicode): - error = error.encode('utf-8', errors='replace') super(OperationFailure, self).__init__( - error, error_labels=error_labels) + _format_detailed_error(error, details), error_labels=error_labels) self.__code = code self.__details = details diff --git a/test/test_errors.py b/test/test_errors.py index 2cb1a0a6b1..9e0685e539 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -33,7 +33,8 @@ def test_not_master_error(self): self.assertIn("full error", traceback.format_exc()) def test_operation_failure(self): - exc = OperationFailure("operation failure test", 10, {"ok": 0, "errmsg":"error"}) + exc = OperationFailure("operation failure test", 10, + {"ok": 0, "errmsg":"error"}) self.assertIn("full error", str(exc)) try: raise exc @@ -42,20 +43,24 @@ def test_operation_failure(self): def _test_unicode_strs(self, exc): if sys.version_info[0] == 2: - self.assertEqual("unicode \xf0\x9f\x90\x8d, full error: {'ok': 0, 'errmsg': u'unicode \\U0001f40d'}", str(exc)) + self.assertEqual("unicode \xf0\x9f\x90\x8d, full error: {'ok': 0, " + "'errmsg': u'unicode \\U0001f40d'}", str(exc)) else: - self.assertEqual("unicode \U0001f40d, full error: {'ok': 0, 'errmsg': 'unicode \U0001f40d'}", str(exc)) + self.assertEqual("unicode \U0001f40d, full error: {'ok': 0, " + "'errmsg': 'unicode \U0001f40d'}", str(exc)) try: raise exc except Exception: self.assertIn("full error", traceback.format_exc()) def test_unicode_strs_operation_failure(self): - exc = OperationFailure(u'unicode \U0001f40d', 10, {"ok": 0, "errmsg": u'unicode \U0001f40d'}) + exc = OperationFailure(u'unicode \U0001f40d', 10, + {"ok": 0, "errmsg": u'unicode \U0001f40d'}) self._test_unicode_strs(exc) def test_unicode_strs_not_master_error(self): - exc = NotMasterError(u'unicode \U0001f40d', {"ok": 0, "errmsg": u'unicode \U0001f40d'}) + exc = NotMasterError(u'unicode \U0001f40d', + {"ok": 0, "errmsg": u'unicode \U0001f40d'}) self._test_unicode_strs(exc) From 71c60dabf6595b2662638d3caca7e93b44ae41e0 Mon Sep 17 00:00:00 2001 From: Julius Park Date: Thu, 2 Jul 2020 13:15:24 -0400 Subject: [PATCH 08/10] fixed issues with unordered dicts --- test/test_database.py | 2 +- test/test_errors.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/test_database.py b/test/test_database.py index 43fac30b0e..6feb1a84e9 100644 --- a/test/test_database.py +++ b/test/test_database.py @@ -959,7 +959,7 @@ def test_command_response_without_ok(self): try: helpers._check_command_response({'$err': 'foo'}) except OperationFailure as e: - self.assertEqual(e.args[0], 'foo') + self.assertEqual(e.args[0], "foo, full error: {'$err': 'foo'}") else: self.fail("_check_command_response didn't raise OperationFailure") diff --git a/test/test_errors.py b/test/test_errors.py index 9e0685e539..9eef7a6a4f 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -25,7 +25,7 @@ class TestErrors(PyMongoTestCase): def test_not_master_error(self): - exc = NotMasterError("not master test", {"ok": 0, "errmsg":"error"}) + exc = NotMasterError("not master test", {"errmsg": "error"}) self.assertIn("full error", str(exc)) try: raise exc @@ -34,7 +34,7 @@ def test_not_master_error(self): def test_operation_failure(self): exc = OperationFailure("operation failure test", 10, - {"ok": 0, "errmsg":"error"}) + {"errmsg": "error"}) self.assertIn("full error", str(exc)) try: raise exc @@ -43,10 +43,10 @@ def test_operation_failure(self): def _test_unicode_strs(self, exc): if sys.version_info[0] == 2: - self.assertEqual("unicode \xf0\x9f\x90\x8d, full error: {'ok': 0, " + self.assertEqual("unicode \xf0\x9f\x90\x8d, full error: {" "'errmsg': u'unicode \\U0001f40d'}", str(exc)) else: - self.assertEqual("unicode \U0001f40d, full error: {'ok': 0, " + self.assertEqual("unicode \U0001f40d, full error: {" "'errmsg': 'unicode \U0001f40d'}", str(exc)) try: raise exc @@ -55,12 +55,12 @@ def _test_unicode_strs(self, exc): def test_unicode_strs_operation_failure(self): exc = OperationFailure(u'unicode \U0001f40d', 10, - {"ok": 0, "errmsg": u'unicode \U0001f40d'}) + {"errmsg": u'unicode \U0001f40d'}) self._test_unicode_strs(exc) def test_unicode_strs_not_master_error(self): exc = NotMasterError(u'unicode \U0001f40d', - {"ok": 0, "errmsg": u'unicode \U0001f40d'}) + {"errmsg": u'unicode \U0001f40d'}) self._test_unicode_strs(exc) From bf46a51a112bb27572a8188663fc50084d882993 Mon Sep 17 00:00:00 2001 From: Julius Park Date: Thu, 2 Jul 2020 13:17:51 -0400 Subject: [PATCH 09/10] updated .gitignore --- .gitignore | 1 + .idea/codeStyles/codeStyleConfig.xml | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.gitignore b/.gitignore index 385160b014..de435d109e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ pymongo.egg-info/ *.egg .tox mongocryptd.pid +.idea/ diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a179b..0000000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file From a2274c21093dd58dab438a3b366d6885055de6b3 Mon Sep 17 00:00:00 2001 From: Julius Park Date: Thu, 2 Jul 2020 13:44:14 -0400 Subject: [PATCH 10/10] Fixed pypy errors due to unicode handling --- test/test_errors.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_errors.py b/test/test_errors.py index 9eef7a6a4f..32d7af3284 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -45,6 +45,10 @@ def _test_unicode_strs(self, exc): if sys.version_info[0] == 2: self.assertEqual("unicode \xf0\x9f\x90\x8d, full error: {" "'errmsg': u'unicode \\U0001f40d'}", str(exc)) + elif 'PyPy' in sys.version: + # PyPy displays unicode in repr differently. + self.assertEqual("unicode \U0001f40d, full error: {" + "'errmsg': 'unicode \\U0001f40d'}", str(exc)) else: self.assertEqual("unicode \U0001f40d, full error: {" "'errmsg': 'unicode \U0001f40d'}", str(exc))