From e9969e6db8a00153ae65d60b312b1e5a2db457ee Mon Sep 17 00:00:00 2001 From: Eric Hare Date: Tue, 7 Nov 2023 09:41:01 -0800 Subject: [PATCH] Fix #78 : HTTP/2 Support for Python Client --- astrapy/endpoints/__init__.py | 13 -- astrapy/endpoints/ops.py | 339 ---------------------------------- astrapy/endpoints/rest.py | 71 ------- astrapy/endpoints/test.py | 0 astrapy/utils.py | 7 +- requirements.txt | 3 +- 6 files changed, 6 insertions(+), 427 deletions(-) delete mode 100644 astrapy/endpoints/__init__.py delete mode 100644 astrapy/endpoints/ops.py delete mode 100644 astrapy/endpoints/rest.py delete mode 100644 astrapy/endpoints/test.py diff --git a/astrapy/endpoints/__init__.py b/astrapy/endpoints/__init__.py deleted file mode 100644 index 2c9ca172..00000000 --- a/astrapy/endpoints/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright DataStax, 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. diff --git a/astrapy/endpoints/ops.py b/astrapy/endpoints/ops.py deleted file mode 100644 index 58487db5..00000000 --- a/astrapy/endpoints/ops.py +++ /dev/null @@ -1,339 +0,0 @@ -# Copyright DataStax, 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. - -from astrapyjson.client import http_methods, DEFAULT_TIMEOUT -import copy -import requests - -DEFAULT_HOST = "https://api.astra.datastax.com" -PATH_PREFIX = "/v2" - - -class AstraOps: - def __init__(self, client=None): - self.client = copy.deepcopy(client) - self.client.base_url = DEFAULT_HOST - self.client.auth_header = "Authorization" - self.client.astra_application_token = ( - f"Bearer {self.client.astra_application_token}" - ) - - def get_databases(self, options=None): - options = {} if options is None else options - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/databases", url_params=options - ) - - def create_database(self, database_definition=None): - r = requests.request( - method=http_methods.POST, - url=f"{self.client.base_url}{PATH_PREFIX}/databases", - json=database_definition, - timeout=DEFAULT_TIMEOUT, - headers={self.client.auth_header: self.client.astra_application_token}, - ) - if r.status_code == 201: - return {"id": r.headers["Location"]} - return None - - def terminate_database(self, database=""): - r = requests.request( - method=http_methods.POST, - url=f"{self.client.base_url}{PATH_PREFIX}/databases/{database}/terminate", - timeout=DEFAULT_TIMEOUT, - headers={self.client.auth_header: self.client.astra_application_token}, - ) - if r.status_code == 202: - return database - return None - - def get_database(self, database=""): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/databases/{database}" - ) - - def create_keyspace(self, database="", keyspace=""): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/databases/{database}/keyspaces/{keyspace}", - ) - - def park_database(self, database=""): - return self.client.request( - method=http_methods.POST, path=f"{PATH_PREFIX}/databases/{database}/park" - ) - - def unpark_database(self, database=""): - return self.client.request( - method=http_methods.POST, path=f"{PATH_PREFIX}/databases/{database}/unpark" - ) - - def resize_database(self, database="", options=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/databases/{database}/resize", - json_data=options, - ) - - def reset_database_password(self, database="", options=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/databases/{database}/resetPassword", - json_data=options, - ) - - def get_secure_bundle(self, database=""): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/databases/{database}/secureBundleURL", - ) - - def get_datacenters(self, database=""): - return self.client.request( - method=http_methods.GET, - path=f"{PATH_PREFIX}/databases/{database}/datacenters", - ) - - def create_datacenter(self, database="", options=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/databases/{database}/datacenters", - json_data=options, - ) - - def terminate_datacenter(self, database="", datacenter=""): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/databases/{database}/datacenters/{datacenter}/terminate", - ) - - def get_access_list(self, database=""): - return self.client.request( - method=http_methods.GET, - path=f"{PATH_PREFIX}/databases/{database}/access-list", - ) - - def replace_access_list(self, database="", access_list=None): - return self.client.request( - method=http_methods.PUT, - path=f"{PATH_PREFIX}/databases/{database}/access-list", - json_data=access_list, - ) - - def update_access_list(self, database="", access_list=None): - return self.client.request( - method=http_methods.PATCH, - path=f"{PATH_PREFIX}/databases/{database}/access-list", - json_data=access_list, - ) - - def add_access_list_address(self, database="", address=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/databases/{database}/access-list", - json_data=address, - ) - - def delete_access_list(self, database=""): - return self.client.request( - method=http_methods.DELETE, - path=f"{PATH_PREFIX}/databases/{database}/access-list", - ) - - def get_private_link(self, database=""): - return self.client.request( - method=http_methods.GET, - path=f"{PATH_PREFIX}/organizations/clusters/{database}/private-link", - ) - - def get_datacenter_private_link(self, database="", datacenter=""): - return self.client.request( - method=http_methods.GET, - path=f"{PATH_PREFIX}/organizations/clusters/{database}/datacenters/{datacenter}/private-link", - ) - - def create_datacenter_private_link( - self, database="", datacenter="", private_link=None - ): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/organizations/clusters/{database}/datacenters/{datacenter}/private-link", - json_data=private_link, - ) - - def create_datacenter_endpoint(self, database="", datacenter="", endpoint=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/organizations/clusters/{database}/datacenters/{datacenter}/endpoint", - json_data=endpoint, - ) - - def update_datacenter_endpoint(self, database="", datacenter="", endpoint=None): - return self.client.request( - method=http_methods.PUT, - path=f"{PATH_PREFIX}/organizations/clusters/{database}/datacenters/{datacenter}/endpoints/{endpoint['id']}", - json_data=endpoint, - ) - - def get_datacenter_endpoint(self, database="", datacenter="", endpoint=""): - return self.client.request( - method=http_methods.GET, - path=f"{PATH_PREFIX}/organizations/clusters/{database}/datacenters/{datacenter}/endpoints/{endpoint}", - ) - - def delete_datacenter_endpoint(self, database="", datacenter="", endpoint=""): - return self.client.request( - method=http_methods.DELETE, - path=f"{PATH_PREFIX}/organizations/clusters/{database}/datacenters/{datacenter}/endpoints/{endpoint}", - ) - - def get_available_classic_regions(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/availableRegions" - ) - - def get_available_regions(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/regions/serverless" - ) - - def get_roles(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/organizations/roles" - ) - - def create_role(self, role_definition=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/organizations/roles", - json_data=role_definition, - ) - - def get_role(self, role=""): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/organizations/roles/{role}" - ) - - def update_role(self, role="", role_definition=None): - return self.client.request( - method=http_methods.PUT, - path=f"{PATH_PREFIX}/organizations/roles/{role}", - json_data=role_definition, - ) - - def delete_role(self, role=""): - return self.client.request( - method=http_methods.DELETE, path=f"{PATH_PREFIX}/organizations/roles/{role}" - ) - - def invite_user(self, user_definition=None): - return self.client.request( - method=http_methods.PUT, - path=f"{PATH_PREFIX}/organizations/users", - json_data=user_definition, - ) - - def get_users(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/organizations/users" - ) - - def get_user(self, user=""): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/organizations/users/{user}" - ) - - def remove_user(self, user=""): - return self.client.request( - method=http_methods.DELETE, path=f"{PATH_PREFIX}/organizations/users/{user}" - ) - - def update_user_roles(self, user="", roles=None): - return self.client.request( - method=http_methods.PUT, - path=f"{PATH_PREFIX}/organizations/users/{user}/roles", - json_data=roles, - ) - - def get_clients(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/clientIdSecrets" - ) - - def create_token(self, roles=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/clientIdSecrets", - json_data=roles, - ) - - def delete_token(self, token=""): - return self.client.request( - method=http_methods.DELETE, path=f"{PATH_PREFIX}/clientIdSecret/{token}" - ) - - def get_organization(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/currentOrg" - ) - - def get_access_lists(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/access-lists" - ) - - def get_access_list_template(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/access-list/template" - ) - - def validate_access_list(self): - return self.client.request( - method=http_methods.POST, path=f"{PATH_PREFIX}/access-list/validate" - ) - - def get_private_links(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/organizations/private-link" - ) - - def get_streaming_providers(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/streaming/providers" - ) - - def get_streaming_tenants(self): - return self.client.request( - method=http_methods.GET, path=f"{PATH_PREFIX}/streaming/tenants" - ) - - def create_streaming_tenant(self, tenant=None): - return self.client.request( - method=http_methods.POST, - path=f"{PATH_PREFIX}/streaming/tenants", - json_data=tenant, - ) - - def delete_streaming_tenant(self, tenant="", cluster=""): - return self.client.request( - method=http_methods.DELETE, - path=f"{PATH_PREFIX}/streaming/tenants/{tenant}/clusters/{cluster}", - json_data=tenant, - ) - - def get_streaming_tenant(self, tenant=""): - return self.client.request( - method=http_methods.GET, - path=f"{PATH_PREFIX}/streaming/tenants/{tenant}/limits", - ) diff --git a/astrapy/endpoints/rest.py b/astrapy/endpoints/rest.py deleted file mode 100644 index b5e31981..00000000 --- a/astrapy/endpoints/rest.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright DataStax, 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 json -from astrapyjson.config.rest import http_methods - -DEFAULT_PAGE_SIZE = 20 -PATH_PREFIX = "/api/rest/v2/keyspaces" - - -class AstraRest: - def __init__(self, client=None): - self.client = client - self.path_prefix = PATH_PREFIX - if client.auth_base_url is not None: - self.path_prefix = "/v2/keyspaces" - - def search_table(self, keyspace="", table="", query=None, options=None): - options = {} if options is None else options - request_params = {"where": json.dumps(query), "page-size": DEFAULT_PAGE_SIZE} - request_params.update(options) - return self.client.request( - method=http_methods.GET, - path=f"{self.path_prefix}/{keyspace}/{table}", - url_params=request_params, - ) - - def add_row(self, keyspace="", table="", row=None): - return self.client.request( - method=http_methods.POST, - path=f"{self.path_prefix}/{keyspace}/{table}", - json_data=row, - ) - - def get_rows(self, keyspace="", table="", key_path="", options=None): - return self.client.request( - method=http_methods.GET, - path=f"{self.path_prefix}/{keyspace}/{table}/{key_path}", - json_data=options, - ) - - def replace_rows(self, keyspace="", table="", key_path="", row=""): - return self.client.request( - method=http_methods.PUT, - path=f"{self.path_prefix}/{keyspace}/{table}/{key_path}", - json_data=row, - ) - - def update_rows(self, keyspace="", table="", key_path="", row=""): - return self.client.request( - method=http_methods.PATCH, - path=f"{self.path_prefix}/{keyspace}/{table}/{key_path}", - json_data=row, - ) - - def delete_rows(self, keyspace="", table="", key_path=""): - return self.client.request( - method=http_methods.DELETE, - path=f"{self.path_prefix}/{keyspace}/{table}/{key_path}", - ) diff --git a/astrapy/endpoints/test.py b/astrapy/endpoints/test.py deleted file mode 100644 index e69de29b..00000000 diff --git a/astrapy/utils.py b/astrapy/utils.py index cf0d03c3..daf44240 100644 --- a/astrapy/utils.py +++ b/astrapy/utils.py @@ -1,4 +1,4 @@ -import requests +import httpx import logging import re @@ -8,6 +8,9 @@ logger = logging.getLogger(__name__) # logger.setLevel(logging.DEBUG) # Apply if wishing to debug requests +# Get an httpx client that is explicitly set to use http2 +client = httpx.Client(http2=True) + class http_methods: GET = "GET" @@ -42,7 +45,7 @@ def make_request( json_data=None, url_params=None, ): - r = requests.request( + r = client.request( method=method, url=f"{base_url}{path}", params=url_params, diff --git a/requirements.txt b/requirements.txt index f2a3293c..257a7cae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,7 @@ faker~=19.11.0 pytest~=7.4.2 pytest-cov~=4.1.0 pytest-testdox~=3.1.0 -requests~=2.31.0 -requests-toolbelt~=1.0.0 +httpx[http2]~=0.25.1 python-dotenv~=1.0.0 pre-commit~=3.5.0 cassio~=0.1.3