From 0f345d847c5db22d7e3ffc1836e25a1bdc098f27 Mon Sep 17 00:00:00 2001 From: Kevin Tian Date: Thu, 2 Jan 2025 17:00:39 -0500 Subject: [PATCH] Add content/accept headers to appropriate http requests (#2088) * Add content-header to http requests * Add accept header * Refactor and add api version * Add simple test --- qiskit_ibm_runtime/api/rest/base.py | 5 +++++ qiskit_ibm_runtime/api/rest/cloud_backend.py | 8 ++++---- qiskit_ibm_runtime/api/rest/program_job.py | 11 ++++++++--- qiskit_ibm_runtime/api/rest/root.py | 12 ++++++++---- qiskit_ibm_runtime/api/rest/runtime.py | 12 ++++++++---- qiskit_ibm_runtime/api/rest/runtime_session.py | 7 ++++--- test/unit/test_runtime_client.py | 5 +++++ 7 files changed, 42 insertions(+), 18 deletions(-) diff --git a/qiskit_ibm_runtime/api/rest/base.py b/qiskit_ibm_runtime/api/rest/base.py index 809dc606f..2e8ea5e16 100644 --- a/qiskit_ibm_runtime/api/rest/base.py +++ b/qiskit_ibm_runtime/api/rest/base.py @@ -23,6 +23,10 @@ class RestAdapterBase: _HEADER_JSON_CONTENT = {"Content-Type": "application/json"} + _HEADER_JSON_ACCEPT = {"Accept": "application/json"} + + _HEADER_API_VERSION = {"IBM-API-Version": "2024-01-01"} + def __init__(self, session: RetrySession, prefix_url: str = "") -> None: """RestAdapterBase constructor. @@ -31,6 +35,7 @@ def __init__(self, session: RetrySession, prefix_url: str = "") -> None: prefix_url: String to be prepend to all URLs. """ self.session = session + self.session.headers = self._HEADER_API_VERSION self.prefix_url = prefix_url def get_url(self, identifier: str) -> str: diff --git a/qiskit_ibm_runtime/api/rest/cloud_backend.py b/qiskit_ibm_runtime/api/rest/cloud_backend.py index 7964e5d58..b9d38d950 100644 --- a/qiskit_ibm_runtime/api/rest/cloud_backend.py +++ b/qiskit_ibm_runtime/api/rest/cloud_backend.py @@ -47,7 +47,7 @@ def configuration(self) -> Dict[str, Any]: JSON response of backend configuration. """ url = self.get_url("configuration") - return self.session.get(url).json() + return self.session.get(url, headers=self._HEADER_JSON_ACCEPT).json() def properties(self, datetime: Optional[python_datetime] = None) -> Dict[str, Any]: """Return backend properties. @@ -61,7 +61,7 @@ def properties(self, datetime: Optional[python_datetime] = None) -> Dict[str, An if datetime: params["updated_before"] = datetime.isoformat() - response = self.session.get(url, params=params).json() + response = self.session.get(url, params=params, headers=self._HEADER_JSON_ACCEPT).json() # Adjust name of the backend. if response: response["backend_name"] = self.backend_name @@ -74,7 +74,7 @@ def pulse_defaults(self) -> Dict[str, Any]: JSON response of pulse defaults. """ url = self.get_url("pulse_defaults") - return self.session.get(url).json() + return self.session.get(url, headers=self._HEADER_JSON_ACCEPT).json() def status(self) -> Dict[str, Any]: """Return backend status. @@ -83,7 +83,7 @@ def status(self) -> Dict[str, Any]: JSON response of backend status. """ url = self.get_url("status") - response = self.session.get(url).json() + response = self.session.get(url, headers=self._HEADER_JSON_ACCEPT).json() # Adjust fields according to the specs (BackendStatus). ret = { "backend_name": self.backend_name, diff --git a/qiskit_ibm_runtime/api/rest/program_job.py b/qiskit_ibm_runtime/api/rest/program_job.py index e50d10af7..18bb64d58 100644 --- a/qiskit_ibm_runtime/api/rest/program_job.py +++ b/qiskit_ibm_runtime/api/rest/program_job.py @@ -56,7 +56,10 @@ def get(self, exclude_params: bool = None) -> Dict: payload = {} if exclude_params: payload["exclude_params"] = "true" - return self.session.get(self.get_url("self"), params=payload).json(cls=RuntimeDecoder) + + return self.session.get( + self.get_url("self"), params=payload, headers=self._HEADER_JSON_ACCEPT + ).json(cls=RuntimeDecoder) def delete(self) -> None: """Delete program job.""" @@ -98,7 +101,7 @@ def metadata(self) -> Dict: Returns: Job Metadata. """ - return self.session.get(self.get_url("metrics")).json() + return self.session.get(self.get_url("metrics"), headers=self._HEADER_JSON_ACCEPT).json() def update_tags(self, tags: list) -> Response: """Update job tags. @@ -106,4 +109,6 @@ def update_tags(self, tags: list) -> Response: Returns: API Response. """ - return self.session.put(self.get_url("tags"), data=json.dumps({"tags": tags})) + return self.session.put( + self.get_url("tags"), data=json.dumps({"tags": tags}), headers=self._HEADER_JSON_CONTENT + ) diff --git a/qiskit_ibm_runtime/api/rest/root.py b/qiskit_ibm_runtime/api/rest/root.py index f5f47af70..7cd868248 100644 --- a/qiskit_ibm_runtime/api/rest/root.py +++ b/qiskit_ibm_runtime/api/rest/root.py @@ -53,7 +53,8 @@ def hubs(self) -> List[Dict[str, Any]]: JSON response. """ url = self.get_url("hubs") - return self.session.get(url).json() + + return self.session.get(url, headers=self._HEADER_JSON_ACCEPT).json() def version(self) -> Dict[str, Union[str, bool]]: """Return the version information. @@ -69,7 +70,7 @@ def version(self) -> Dict[str, Union[str, bool]]: * ``api-*`` (str): The versions of each individual API component """ url = self.get_url("version") - response = self.session.get(url) + response = self.session.get(url, headers=self._HEADER_JSON_ACCEPT) try: version_info = response.json() @@ -89,7 +90,9 @@ def login(self, api_token: str) -> Dict[str, Any]: JSON response. """ url = self.get_url("login") - return self.session.post(url, json={"apiToken": api_token}).json() + return self.session.post( + url, json={"apiToken": api_token}, headers=self._HEADER_JSON_CONTENT + ).json() def user_info(self) -> Dict[str, Any]: """Return user information. @@ -98,6 +101,7 @@ def user_info(self) -> Dict[str, Any]: JSON response of user information. """ url = self.get_url("user_info") - response = self.session.get(url).json() + + response = self.session.get(url, headers=self._HEADER_JSON_ACCEPT).json() return response diff --git a/qiskit_ibm_runtime/api/rest/runtime.py b/qiskit_ibm_runtime/api/rest/runtime.py index 45d39e77b..829f73fcb 100644 --- a/qiskit_ibm_runtime/api/rest/runtime.py +++ b/qiskit_ibm_runtime/api/rest/runtime.py @@ -126,7 +126,9 @@ def program_run( if private: payload["private"] = True data = json.dumps(payload, cls=RuntimeEncoder) - return self.session.post(url, data=data, timeout=900).json() + return self.session.post( + url, data=data, timeout=900, headers=self._HEADER_JSON_CONTENT + ).json() def jobs_get( self, @@ -195,7 +197,7 @@ def jobs_get( payload["sort"] = "ASC" if all([hub, group, project]): payload["provider"] = f"{hub}/{group}/{project}" - return self.session.get(url, params=payload).json() + return self.session.get(url, params=payload, headers=self._HEADER_JSON_ACCEPT).json() def backend(self, backend_name: str) -> CloudBackend: """Return an adapter for the IBM backend. @@ -226,7 +228,9 @@ def backends( params = {} if hgp: params["provider"] = hgp - return self.session.get(url, params=params, timeout=timeout).json() + return self.session.get( + url, params=params, timeout=timeout, headers=self._HEADER_JSON_ACCEPT + ).json() def usage(self) -> Dict[str, Any]: """Return monthly open plan usage information. @@ -235,4 +239,4 @@ def usage(self) -> Dict[str, Any]: JSON response. """ url = self.get_url("usage") - return self.session.get(url).json() + return self.session.get(url, headers=self._HEADER_JSON_ACCEPT).json() diff --git a/qiskit_ibm_runtime/api/rest/runtime_session.py b/qiskit_ibm_runtime/api/rest/runtime_session.py index 7a585b54e..74fca7ad8 100644 --- a/qiskit_ibm_runtime/api/rest/runtime_session.py +++ b/qiskit_ibm_runtime/api/rest/runtime_session.py @@ -62,7 +62,7 @@ def create( payload["max_session_ttl"] = max_time # type: ignore[assignment] else: payload["max_ttl"] = max_time # type: ignore[assignment] - return self.session.post(url, json=payload).json() + return self.session.post(url, json=payload, headers=self._HEADER_JSON_CONTENT).json() def cancel(self) -> None: """Cancel all jobs in the session.""" @@ -74,7 +74,7 @@ def close(self) -> None: payload = {"accepting_jobs": False} url = self.get_url("self") try: - self.session.patch(url, json=payload) + self.session.patch(url, json=payload, headers=self._HEADER_JSON_CONTENT) except RequestsApiError as ex: if ex.status_code == 404: pass @@ -83,4 +83,5 @@ def close(self) -> None: def details(self) -> Dict[str, Any]: """Return the details of this session.""" - return self.session.get(self.get_url("self")).json() + + return self.session.get(self.get_url("self"), headers=self._HEADER_JSON_ACCEPT).json() diff --git a/test/unit/test_runtime_client.py b/test/unit/test_runtime_client.py index 241684de0..c8328ce86 100644 --- a/test/unit/test_runtime_client.py +++ b/test/unit/test_runtime_client.py @@ -85,3 +85,8 @@ def test_custom_client_app_header(self): client._session.custom_header = None client._session._set_custom_header() self.assertNotIn(custom_header, client._session.headers["X-Qx-Client-Application"]) + + def test_header_api_version(self): + """Test IBM-API-Version is in header.""" + client = self._get_client() + self.assertIn("IBM-API-Version", client._session.headers)