From 7bd96c7408cd9d3a9d2d6c3696de3abf845c64c1 Mon Sep 17 00:00:00 2001 From: dshylov Date: Mon, 5 Oct 2020 17:06:25 +0300 Subject: [PATCH 01/12] MAPRDB-2313 Update Python Client (MAPRDB-2308 Support Special Characters in OJAI Connection String) --- mapr/ojai/storage/OJAIConnection.py | 38 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/mapr/ojai/storage/OJAIConnection.py b/mapr/ojai/storage/OJAIConnection.py index cf56be3..4c25330 100644 --- a/mapr/ojai/storage/OJAIConnection.py +++ b/mapr/ojai/storage/OJAIConnection.py @@ -101,27 +101,41 @@ def __ping_connection(self, connection): @staticmethod def __parse_connection_url(connection_str): try: - url, options = re.sub('ojai:mapr:thin:v1@', '', connection_str).split('?', 1) + url, options = re.sub('ojai:mapr:thin:v1@', '', + connection_str).split('?', 1) except TypeError as e: - raise IllegalArgumentError(m='Connection string type must be str, but was {0}. \n{1}' - .format(type(connection_str), e)) + raise IllegalArgumentError( + m='Connection string type must be str, but was {0}. \n{1}' + .format(type(connection_str), e)) except ValueError as e: raise ValueError('{0}. \n{1}' .format(e, 'Common url string format' ' is [:][?].')) - options_dict = (urllib.parse.parse_qs(urllib.parse.urlparse(connection_str).query)) - auth = options_dict.get('auth', ['basic'])[0] - key = '{0}:{1}'.format(options_dict.get('user', [''])[0], options_dict.get('password', [''])[0]).encode() + options_dict = ( + urllib.parse.parse_qs(urllib.parse.urlparse(connection_str).query)) + auth = urllib.unquote(options_dict.get('auth', ['basic'])[0]) + user = urllib.unquote(options_dict.get('user', [''])[0]) + password = urllib.unquote(options_dict.get('password', [''])[0]) + key = '{0}:{1}'.format(user, password) encoded_user_metadata = base64.b64encode(key).decode() - ssl = True if options_dict.get('ssl', ['true'])[0] == 'true' else False - ssl_ca = options_dict.get('sslCA', [''])[0] - ssl_target_name_override = options_dict.get('sslTargetNameOverride', [''])[0] + ssl = \ + True if urllib.unquote( + options_dict.get('ssl', ['true'])[0]) == 'true' else False + ssl_ca = urllib.unquote(options_dict.get('sslCA', [''])[0]) + ssl_target_name_override = \ + urllib.unquote(options_dict.get('sslTargetNameOverride', [''])[0]) if ssl and ssl_ca == '': - raise AttributeError('sslCa path must be specified when ssl enabled.') - - return url, auth, encoded_user_metadata, ssl, ssl_ca, ssl_target_name_override + raise AttributeError( + 'sslCa path must be specified when ssl enabled.') + + return url,\ + auth,\ + encoded_user_metadata,\ + ssl,\ + ssl_ca,\ + ssl_target_name_override @staticmethod def __get_channel(url, From e50f23e052dadc69f1f0c69dafe985a82cdd970f Mon Sep 17 00:00:00 2001 From: dshylov Date: Fri, 9 Oct 2020 14:41:10 +0300 Subject: [PATCH 02/12] MAPRDB-2313 Update Python Client (MAPRDB-2308 Support Special Characters in OJAI Connection String) Fixed a python3 compatibility issue. Updated version. --- mapr/ojai/storage/OJAIConnection.py | 27 ++++++++++++++------------- setup.py | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/mapr/ojai/storage/OJAIConnection.py b/mapr/ojai/storage/OJAIConnection.py index 4c25330..d55d602 100644 --- a/mapr/ojai/storage/OJAIConnection.py +++ b/mapr/ojai/storage/OJAIConnection.py @@ -106,7 +106,7 @@ def __parse_connection_url(connection_str): except TypeError as e: raise IllegalArgumentError( m='Connection string type must be str, but was {0}. \n{1}' - .format(type(connection_str), e)) + .format(type(connection_str), e)) except ValueError as e: raise ValueError('{0}. \n{1}' .format(e, @@ -114,27 +114,28 @@ def __parse_connection_url(connection_str): ' is [:][?].')) options_dict = ( urllib.parse.parse_qs(urllib.parse.urlparse(connection_str).query)) - auth = urllib.unquote(options_dict.get('auth', ['basic'])[0]) - user = urllib.unquote(options_dict.get('user', [''])[0]) - password = urllib.unquote(options_dict.get('password', [''])[0]) - key = '{0}:{1}'.format(user, password) + auth = urllib.parse.unquote(options_dict.get('auth', ['basic'])[0]) + user = urllib.parse.unquote(options_dict.get('user', [''])[0]) + password = urllib.parse.unquote(options_dict.get('password', [''])[0]) + key = '{0}:{1}'.format(user, password).encode() encoded_user_metadata = base64.b64encode(key).decode() ssl = \ - True if urllib.unquote( + True if urllib.parse.unquote( options_dict.get('ssl', ['true'])[0]) == 'true' else False - ssl_ca = urllib.unquote(options_dict.get('sslCA', [''])[0]) + ssl_ca = urllib.parse.unquote(options_dict.get('sslCA', [''])[0]) ssl_target_name_override = \ - urllib.unquote(options_dict.get('sslTargetNameOverride', [''])[0]) + urllib.parse.unquote( + options_dict.get('sslTargetNameOverride', [''])[0]) if ssl and ssl_ca == '': raise AttributeError( 'sslCa path must be specified when ssl enabled.') - return url,\ - auth,\ - encoded_user_metadata,\ - ssl,\ - ssl_ca,\ + return url, \ + auth, \ + encoded_user_metadata, \ + ssl, \ + ssl_ca, \ ssl_target_name_override @staticmethod diff --git a/setup.py b/setup.py index 088502e..4bbe295 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup(name='maprdb_python_client', - version='1.1.3', + version='1.1.4', description='MapR-DB Python Client', url='https://github.com/mapr/maprdb-python-client/', author='MapR, Inc.', From 8d226fb53c1868a2165bbfab08d42f7de29b78b0 Mon Sep 17 00:00:00 2001 From: Ted Dunning Date: Tue, 15 Dec 2020 09:13:28 -0800 Subject: [PATCH 03/12] Update doc link to latest version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2fbbfdc..4edda6b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A simple, lightweight library that provides access to MapR-DB. The client library supports all existing OJAI functionality and is absolutely compatible with Java OJAI connector, that runs under the MapR Data Access Gateway. -The MapR official documentation [link](https://mapr.com/docs/61/MapR-DB/JSON_DB/UsingPythonOJAIClient.html). +The MapR official documentation [link](https://mapr.com/docs/62/MapR-DB/JSON_DB/UsingPythonOJAIClient.html). To install the client library into your application, you need to follow these [install instructions](https://github.com/mapr/maprdb-python-client/blob/master/install_client.md). From e7ba152c5b4028a0df0ee2de9159ac9037e4dba1 Mon Sep 17 00:00:00 2001 From: dshylov Date: Fri, 22 Jan 2021 19:54:57 +0200 Subject: [PATCH 04/12] MAPRDB-2366 [maprdb ojai python client] Expected response on check_and_replace changed. --- mapr/ojai/storage/OJAIDocumentStore.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mapr/ojai/storage/OJAIDocumentStore.py b/mapr/ojai/storage/OJAIDocumentStore.py index 24123d3..b240775 100644 --- a/mapr/ojai/storage/OJAIDocumentStore.py +++ b/mapr/ojai/storage/OJAIDocumentStore.py @@ -380,8 +380,12 @@ def check_and_replace(self, doc, condition, _id=None): doc_str = OJAIDocumentStore.__get_doc_str(doc=doc, _id=_id) str_condition = OJAIDocumentStore.__get_str_condition( condition=condition) - self.__evaluate_doc(doc_str=doc_str, operation_type='REPLACE', - condition=str_condition) + try: + self.__evaluate_doc(doc_str=doc_str, operation_type='REPLACE', + condition=str_condition) + except DocumentNotFoundError: + return False + return True @staticmethod def __validate_document(doc_to_insert): From 01885b959e3a635184f8da404575a8b2fd78b33f Mon Sep 17 00:00:00 2001 From: dshylov Date: Thu, 18 Feb 2021 17:31:51 +0200 Subject: [PATCH 05/12] MAPRDB-2436 Issue adding a list of records to maprdb with maprdb-python-client --- mapr/ojai/ojai_utils/ojai_list.py | 1 + test/document/test_document_with_tags.py | 32 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/mapr/ojai/ojai_utils/ojai_list.py b/mapr/ojai/ojai_utils/ojai_list.py index 0abc491..952148f 100644 --- a/mapr/ojai/ojai_utils/ojai_list.py +++ b/mapr/ojai/ojai_utils/ojai_list.py @@ -34,6 +34,7 @@ def set_list(value, tags=False): else: internal_value = dump_document.set('dump', v).as_dictionary()['dump'] tmp_dict[k] = internal_value + dump_document.clear() ojai_list.append(tmp_dict) else: ojai_list.append(dump_document.set('dump', elem).as_dictionary()['dump']) diff --git a/test/document/test_document_with_tags.py b/test/document/test_document_with_tags.py index dc8300c..9fce970 100644 --- a/test/document/test_document_with_tags.py +++ b/test/document/test_document_with_tags.py @@ -239,3 +239,35 @@ def test_list_with_nested_dict(self): "surname": "Surname", "city": "City"}]})) self.assertEqual(doc.as_json_str(with_tags=False), json.dumps({"_id": "some_id", "list": [{"name": 55, "surname": "Surname", "city": "City"}]})) + + + # MAPRDB-2436 + def test_list_with_multiple_nested_levels(self): + test_doc_dict = \ + {"_id": "some_id", + "list": [ + 0, + {"name": 55, + "data": + {"surname": "Surname", + "city": "City", + "postal": { + "code": 1234, + "tag": "PY" + }}}]} + doc = OJAIDocument().from_dict(test_doc_dict) + self.assertEqual(doc.as_dictionary(), + test_doc_dict) + self.assertEqual(doc.as_json_str(), + json.dumps({"_id": "some_id", + "list": [ + {"$numberLong": 0}, + { + "name": {"$numberLong": 55}, + "data": + {"surname": "Surname", + "city": "City", + "postal": {"code": {"$numberLong": 1234}, + "tag": "PY"}}}]})) + self.assertEqual(doc.as_json_str(with_tags=False), + json.dumps(test_doc_dict)) From bf1f304a463edfb3468eeba7a7984f32447d8d85 Mon Sep 17 00:00:00 2001 From: dshylov Date: Mon, 22 Feb 2021 13:08:49 +0200 Subject: [PATCH 06/12] Update client version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4bbe295..dc76947 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup(name='maprdb_python_client', - version='1.1.4', + version='1.1.5', description='MapR-DB Python Client', url='https://github.com/mapr/maprdb-python-client/', author='MapR, Inc.', From 2767033ae7edb4528a61b328d87c77169b92df75 Mon Sep 17 00:00:00 2001 From: ttereshchenko Date: Wed, 30 Mar 2022 21:26:14 +0300 Subject: [PATCH 07/12] MAPRDB-2548: - Added generation of 'Access denied' exception, while response has 13 error code --- mapr/ojai/storage/OJAIConnection.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mapr/ojai/storage/OJAIConnection.py b/mapr/ojai/storage/OJAIConnection.py index d55d602..c0a9da2 100644 --- a/mapr/ojai/storage/OJAIConnection.py +++ b/mapr/ojai/storage/OJAIConnection.py @@ -22,6 +22,7 @@ from mapr.ojai.exceptions.ConnectionError import ConnectionError from mapr.ojai.exceptions.IllegalArgumentError import IllegalArgumentError from mapr.ojai.exceptions.PathNotFoundError import PathNotFoundError +from mapr.ojai.exceptions.AccessDeniedError import AccessDeniedError from mapr.ojai.exceptions.StoreAlreadyExistsError import StoreAlreadyExistsError from mapr.ojai.exceptions.StoreNotFoundError import StoreNotFoundError from mapr.ojai.exceptions.UnknownServerError import UnknownServerError @@ -211,6 +212,8 @@ def __validate_response(response): raise StoreAlreadyExistsError(m=response.error.error_message) elif response.error.err_code == ErrorCode.Value('PATH_NOT_FOUND'): raise PathNotFoundError(m=response.error.error_message) + elif response.error.err_code == ErrorCode.Value('ACCESS_DENIED'): + raise AccessDeniedError(m=response.error.error_message) elif response.error.err_code == ErrorCode.Value('TABLE_NOT_FOUND'): return False else: From a7f87a54ac3be37af9ee362d28cbb75b6c9aa969 Mon Sep 17 00:00:00 2001 From: ttereshchenko Date: Mon, 4 Apr 2022 17:51:41 +0200 Subject: [PATCH 08/12] Updated client version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index dc76947..fba6b74 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup(name='maprdb_python_client', - version='1.1.5', + version='1.1.6', description='MapR-DB Python Client', url='https://github.com/mapr/maprdb-python-client/', author='MapR, Inc.', From 91c65ff9475aa2dfc43e79ead48fd2902dad29ae Mon Sep 17 00:00:00 2001 From: ttereshchenko Date: Wed, 30 Mar 2022 20:55:37 +0300 Subject: [PATCH 09/12] MAPRDB-2545: - fixed connection string parser for newer versions of python --- mapr/ojai/storage/OJAIConnection.py | 31 +++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/mapr/ojai/storage/OJAIConnection.py b/mapr/ojai/storage/OJAIConnection.py index c0a9da2..3e29325 100644 --- a/mapr/ojai/storage/OJAIConnection.py +++ b/mapr/ojai/storage/OJAIConnection.py @@ -113,31 +113,28 @@ def __parse_connection_url(connection_str): .format(e, 'Common url string format' ' is [:][?].')) - options_dict = ( - urllib.parse.parse_qs(urllib.parse.urlparse(connection_str).query)) - auth = urllib.parse.unquote(options_dict.get('auth', ['basic'])[0]) - user = urllib.parse.unquote(options_dict.get('user', [''])[0]) - password = urllib.parse.unquote(options_dict.get('password', [''])[0]) - key = '{0}:{1}'.format(user, password).encode() + + options_dict = dict() + for pair in urllib.parse.urlparse(connection_str).query.split(';'): + entry = pair.split('=') + if entry[1:]: + options_dict[entry[0]] = urllib.parse.unquote(entry[1]) + + key = '{0}:{1}'.format(options_dict.get('user', ''), options_dict.get('password', '')).encode() encoded_user_metadata = base64.b64encode(key).decode() - ssl = \ - True if urllib.parse.unquote( - options_dict.get('ssl', ['true'])[0]) == 'true' else False - ssl_ca = urllib.parse.unquote(options_dict.get('sslCA', [''])[0]) - ssl_target_name_override = \ - urllib.parse.unquote( - options_dict.get('sslTargetNameOverride', [''])[0]) - - if ssl and ssl_ca == '': + ssl = json.loads(options_dict.get('ssl', 'true')) + ssl_ca = options_dict.get('sslCA', '') + + if ssl and not ssl_ca: raise AttributeError( 'sslCa path must be specified when ssl enabled.') return url, \ - auth, \ + options_dict.get('auth', 'basic'), \ encoded_user_metadata, \ ssl, \ ssl_ca, \ - ssl_target_name_override + options_dict.get('sslTargetNameOverride', '') @staticmethod def __get_channel(url, From a61b6d2ad797d78ddd8a389477551bde222b2b49 Mon Sep 17 00:00:00 2001 From: ttereshchenko Date: Fri, 8 Apr 2022 16:12:45 +0200 Subject: [PATCH 10/12] MAPRDB-2479: - added support for Escape Character with $like operator --- mapr/ojai/ojai_query/OJAIQueryCondition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mapr/ojai/ojai_query/OJAIQueryCondition.py b/mapr/ojai/ojai_query/OJAIQueryCondition.py index b3768c8..6542c68 100644 --- a/mapr/ojai/ojai_query/OJAIQueryCondition.py +++ b/mapr/ojai/ojai_query/OJAIQueryCondition.py @@ -105,11 +105,11 @@ def not_matches_(self, field_path, regex): return self def like_(self, field_path, like_expression, escape_char=None): - self.__tokens.append({'$like': {field_path: like_expression}}) + self.__tokens.append({'$like': {field_path: [like_expression, escape_char] if escape_char else like_expression}}) return self def not_like_(self, field_path, like_expression, escape_char=None): - self.__tokens.append({'$notlike': {field_path: like_expression}}) + self.__tokens.append({'$notlike': {field_path: [like_expression, escape_char] if escape_char else like_expression}}) return self def is_(self, field_path, op, value): From af6062955f6adaa0b03640cbd864c6e3d15b8272 Mon Sep 17 00:00:00 2001 From: ttereshchenko Date: Fri, 8 Apr 2022 16:22:10 +0200 Subject: [PATCH 11/12] MAPRDB-2479: - added unit tests --- test/query_test/test_query.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/query_test/test_query.py b/test/query_test/test_query.py index 2f98095..32c0a62 100644 --- a/test/query_test/test_query.py +++ b/test/query_test/test_query.py @@ -206,10 +206,18 @@ def test_like(self): qc = OJAIQueryCondition().like_('card', 'visa').close().build() self.assertEqual(qc.as_dictionary(), {'$like': {'card': 'visa'}}) + def test_like_with_escape_character(self): + qc = OJAIQueryCondition().like_('_id', '00\\\\%2%', '\\\\').close().build() + self.assertEqual(qc.as_dictionary(), {'$like': {'_id': ['00\\\\%2%', '\\\\']}}) + def test_not_like(self): qc = OJAIQueryCondition().not_like_('card', 'visa').close().build() self.assertEqual(qc.as_dictionary(), {'$notlike': {'card': 'visa'}}) + def test_not_like_with_escape_character(self): + qc = OJAIQueryCondition().not_like_('_id', '00|%2%', '|').close().build() + self.assertEqual(qc.as_dictionary(), {'$notlike': {'_id': ['00|%2%', '|']}}) + def test_empty_condition(self): qc = OJAIQueryCondition() self.assertTrue(qc.is_empty()) From 3311e3f76a9a25db38025b08b33ffc50f5ad8bf0 Mon Sep 17 00:00:00 2001 From: Aditya Kishore Date: Tue, 5 Dec 2023 22:17:58 -0800 Subject: [PATCH 12/12] Setting next version to 1.1.7 --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fba6b74..07a1310 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,13 @@ setup(name='maprdb_python_client', - version='1.1.6', + version='1.1.7', description='MapR-DB Python Client', url='https://github.com/mapr/maprdb-python-client/', author='MapR, Inc.', keywords='ojai python client mapr maprdb', packages=find_packages(exclude=['test*', 'docs*', 'examples*']), + setup_requires=['wheel'], install_requires=['aenum>=2.0.10', 'grpcio>=1.9.1', 'grpcio-tools>=1.9.1', 'ojai-python-api>=1.1', 'python-dateutil>=2.6.1', 'retrying>=1.3.3', 'future>=0.16.0'], python_requires='>=2.7.*',