Skip to content

Commit

Permalink
Merge branch 'main' into FH/devenv
Browse files Browse the repository at this point in the history
  • Loading branch information
ptristan3 authored Jan 6, 2025
2 parents 5c33be2 + 0f345d8 commit 5f28032
Show file tree
Hide file tree
Showing 16 changed files with 64 additions and 35 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ Integration and E2E tests require an environment configuration and can be run ag
Sample configuration for IBM Quantum
```bash
QISKIT_IBM_TOKEN=... # IBM Quantum API token
QISKIT_IBM_URL=https://auth.quantum-computing.ibm.com/api # IBM Quantum API URL
QISKIT_IBM_URL=https://auth.quantum.ibm.com/api # IBM Quantum API URL
QISKIT_IBM_INSTANCE=ibm-q/open/main # IBM Quantum provider to use (hub/group/project)
QISKIT_IBM_QPU=... # IBM Quantum Processing Unit to use
```
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ Access to IBM Quantum Platform channel is controlled by the instances (previousl

> **_NOTE:_** IBM Cloud instances are different from IBM Quantum Platform instances. IBM Cloud does not use the hub/group/project structure for user management. To view and create IBM Cloud instances, visit the [IBM Cloud Quantum Instances page](https://cloud.ibm.com/quantum/instances).
To view a list of your instances, visit your [account settings page](https://www.quantum-computing.ibm.com/account) or use the `instances()` method.
To view a list of your instances, visit your [account settings page](https://www.quantum.ibm.com/account) or use the `instances()` method.

You can specify an instance when initializing the service or provider, or when picking a backend:

Expand Down Expand Up @@ -352,9 +352,9 @@ If you use Qiskit, please cite as per the included [BibTeX file](https://github.
[Apache License 2.0].


[IBM Quantum]: https://www.ibm.com/quantum-computing/
[IBM Quantum login page]: https://quantum-computing.ibm.com/login
[IBM Quantum account page]: https://quantum-computing.ibm.com/account
[IBM Quantum]: https://www.ibm.com/quantum/
[IBM Quantum login page]: https://quantum.ibm.com/login
[IBM Quantum account page]: https://quantum.ibm.com/account
[contribution guidelines]: https://github.com/Qiskit/qiskit-ibm-runtime/blob/main/CONTRIBUTING.md
[code of conduct]: https://github.com/Qiskit/qiskit-ibm-runtime/blob/main/CODE_OF_CONDUCT.md
[GitHub issues]: https://github.com/Qiskit/qiskit-ibm-runtime/issues
Expand Down
2 changes: 1 addition & 1 deletion qiskit_ibm_runtime/accounts/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
AccountType = Optional[Literal["cloud", "legacy"]]
ChannelType = Optional[Literal["ibm_cloud", "ibm_quantum", "local"]]

IBM_QUANTUM_API_URL = "https://auth.quantum-computing.ibm.com/api"
IBM_QUANTUM_API_URL = "https://auth.quantum.ibm.com/api"
IBM_CLOUD_API_URL = "https://cloud.ibm.com"
logger = logging.getLogger(__name__)

Expand Down
5 changes: 5 additions & 0 deletions qiskit_ibm_runtime/api/rest/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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:
Expand Down
8 changes: 4 additions & 4 deletions qiskit_ibm_runtime/api/rest/cloud_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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,
Expand Down
11 changes: 8 additions & 3 deletions qiskit_ibm_runtime/api/rest/program_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down Expand Up @@ -98,12 +101,14 @@ 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.
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
)
12 changes: 8 additions & 4 deletions qiskit_ibm_runtime/api/rest/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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()
Expand All @@ -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.
Expand All @@ -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
12 changes: 8 additions & 4 deletions qiskit_ibm_runtime/api/rest/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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()
7 changes: 4 additions & 3 deletions qiskit_ibm_runtime/api/rest/runtime_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand All @@ -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
Expand All @@ -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()
2 changes: 1 addition & 1 deletion qiskit_ibm_runtime/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from .utils.runner_result import RunnerResult


QISKIT_IBM_RUNTIME_API_URL = "https://auth.quantum-computing.ibm.com/api"
QISKIT_IBM_RUNTIME_API_URL = "https://auth.quantum.ibm.com/api"

API_TO_JOB_STATUS = {
"QUEUED": JobStatus.QUEUED,
Expand Down
4 changes: 2 additions & 2 deletions qiskit_ibm_runtime/qiskit_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def __init__(
token: IBM Cloud API key or IBM Quantum API token.
url: The API URL.
Defaults to https://cloud.ibm.com (ibm_cloud) or
https://auth.quantum-computing.ibm.com/api (ibm_quantum).
https://auth.quantum.ibm.com/api (ibm_quantum).
filename: Full path of the file where the account is created.
Default: _DEFAULT_ACCOUNT_CONFIG_JSON_FILE
name: Name of the account to load.
Expand Down Expand Up @@ -664,7 +664,7 @@ def save_account(
token: IBM Cloud API key or IBM Quantum API token.
url: The API URL.
Defaults to https://cloud.ibm.com (ibm_cloud) or
https://auth.quantum-computing.ibm.com/api (ibm_quantum).
https://auth.quantum.ibm.com/api (ibm_quantum).
instance: The CRN (ibm_cloud) or hub/group/project (ibm_quantum).
channel: Channel type. `ibm_cloud` or `ibm_quantum`.
filename: Full path of the file where the account is saved.
Expand Down
7 changes: 6 additions & 1 deletion qiskit_ibm_runtime/runtime_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ def __init__(
this time limit, it is forcibly cancelled. Simulator jobs continue to use wall
clock time.
session_time: Length of session in seconds.
private: Boolean of whether or not the job is marked as private.
private: Boolean that indicates whether the job is marked as private. This is only
supported for ``ibm_quantum`` channel. When set to true, input parameters are not
returned, and the results can only be read once. After the results are read or after
a specified time after the job is completed, the results are deleted from the service.
When set to false, the input parameters and results follow the standard retention
behavior.
"""
self.backend = backend
self.image = image
Expand Down
2 changes: 1 addition & 1 deletion test/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def _get_integration_test_config():
os.getenv("QISKIT_IBM_INSTANCE"),
os.getenv("QISKIT_IBM_QPU"),
)
channel: Any = "ibm_quantum" if url.find("quantum-computing.ibm.com") >= 0 else "ibm_cloud"
channel: Any = "ibm_quantum" if url.find("quantum.ibm.com") >= 0 else "ibm_cloud"
return channel, token, url, instance, qpu


Expand Down
4 changes: 2 additions & 2 deletions test/unit/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
_TEST_IBM_QUANTUM_ACCOUNT = Account.create_account(
channel="ibm_quantum",
token="token-x",
url="https://auth.quantum-computing.ibm.com/api",
url="https://auth.quantum.ibm.com/api",
instance="ibm-q/open/main",
)

Expand All @@ -66,7 +66,7 @@ class TestAccount(IBMTestCase):

dummy_token = "123"
dummy_ibm_cloud_url = "https://us-east.quantum-computing.cloud.ibm.com"
dummy_ibm_quantum_url = "https://auth.quantum-computing.ibm.com/api"
dummy_ibm_quantum_url = "https://auth.quantum.ibm.com/api"

def test_skip_crn_resolution_for_crn(self):
"""Test that CRN resolution is skipped if the instance value is already a CRN."""
Expand Down
8 changes: 4 additions & 4 deletions test/unit/test_client_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ def test_get_runtime_api_base_url(self) -> None:
(
"ibm_quantum",
"h/g/p",
"https://auth.quantum-computing.ibm.com/api",
"https://auth.quantum.ibm.com/api",
None,
"https://auth.quantum-computing.ibm.com/api",
"https://auth.quantum.ibm.com/api",
),
(
"ibm_cloud",
Expand All @@ -92,9 +92,9 @@ def test_get_runtime_api_base_url(self) -> None:
(
"ibm_quantum",
"h/g/p",
"https://auth.quantum-computing.ibm.com/api",
"https://auth.quantum.ibm.com/api",
lambda a, b, c: f"{a}:{b}:{c}",
"https://auth.quantum-computing.ibm.com/api:h/g/p:False",
"https://auth.quantum.ibm.com/api:h/g/p:False",
),
]
for spec in test_specs:
Expand Down
5 changes: 5 additions & 0 deletions test/unit/test_runtime_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 5f28032

Please sign in to comment.