Skip to content

Commit

Permalink
add custom url resolver to enable using other endpoints (#1914)
Browse files Browse the repository at this point in the history
* custom url resolver

* deprecate get_runtime_api_base_url
  • Loading branch information
cpkurotori authored Sep 10, 2024
1 parent 7e79b7c commit 0754905
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 6 deletions.
11 changes: 8 additions & 3 deletions qiskit_ibm_runtime/api/client_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

"""Represent IBM Quantum account client parameters."""

from typing import Dict, Optional, Any, Union
from typing import Dict, Optional, Any, Union, Callable
from ..proxies import ProxyConfiguration

from ..utils import get_runtime_api_base_url
from ..utils import default_runtime_url_resolver
from ..api.auth import QuantumAuth, CloudAuth

TEMPLATE_IBM_HUBS = "{prefix}/Network/{hub}/Groups/{group}/Projects/{project}"
Expand All @@ -34,6 +34,7 @@ def __init__(
proxies: Optional[ProxyConfiguration] = None,
verify: bool = True,
private_endpoint: Optional[bool] = False,
url_resolver: Optional[Callable[[str, str, Optional[bool]], str]] = None,
) -> None:
"""ClientParameters constructor.
Expand All @@ -45,6 +46,7 @@ def __init__(
proxies: Proxy configuration.
verify: If ``False``, ignores SSL certificates errors.
private_endpoint: Connect to private API URL.
url_resolver: Function used to resolve the runtime url.
"""
self.token = token
self.instance = instance
Expand All @@ -53,6 +55,9 @@ def __init__(
self.proxies = proxies
self.verify = verify
self.private_endpoint = private_endpoint
if not url_resolver:
url_resolver = default_runtime_url_resolver
self.url_resolver = url_resolver

def get_auth_handler(self) -> Union[CloudAuth, QuantumAuth]:
"""Returns the respective authentication handler."""
Expand All @@ -63,7 +68,7 @@ def get_auth_handler(self) -> Union[CloudAuth, QuantumAuth]:

def get_runtime_api_base_url(self) -> str:
"""Returns the Runtime API base url."""
return get_runtime_api_base_url(self.url, self.instance, self.private_endpoint)
return self.url_resolver(self.url, self.instance, self.private_endpoint)

def connection_parameters(self) -> Dict[str, Any]:
"""Construct connection related parameters.
Expand Down
5 changes: 5 additions & 0 deletions qiskit_ibm_runtime/qiskit_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def __init__(
verify: Optional[bool] = None,
channel_strategy: Optional[str] = None,
private_endpoint: Optional[bool] = None,
url_resolver: Optional[Callable[[str, str, Optional[bool]], str]] = None,
) -> None:
"""QiskitRuntimeService constructor
Expand Down Expand Up @@ -117,6 +118,7 @@ def __init__(
verify: Whether to verify the server's TLS certificate.
channel_strategy: Error mitigation strategy.
private_endpoint: Connect to private API URL.
url_resolver: Function used to resolve the runtime url.
Returns:
An instance of QiskitRuntimeService or QiskitRuntimeLocalService for local channel.
Expand Down Expand Up @@ -149,11 +151,13 @@ def __init__(
proxies=self._account.proxies,
verify=self._account.verify,
private_endpoint=self._account.private_endpoint,
url_resolver=url_resolver,
)

self._channel_strategy = channel_strategy or self._account.channel_strategy
self._channel = self._account.channel
self._backend_allowed_list: List[str] = []
self._url_resolver = url_resolver

if self._channel == "ibm_cloud":
self._api_client = RuntimeClient(self._client_params)
Expand Down Expand Up @@ -359,6 +363,7 @@ def _initialize_hgps(
),
proxies=self._account.proxies,
verify=self._account.verify,
url_resolver=self._url_resolver,
)

# Build the hgp.
Expand Down
1 change: 1 addition & 0 deletions qiskit_ibm_runtime/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
to_python_identifier,
is_crn,
get_runtime_api_base_url,
default_runtime_url_resolver,
resolve_crn,
are_circuits_dynamic,
)
Expand Down
16 changes: 15 additions & 1 deletion qiskit_ibm_runtime/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from qiskit.circuit import QuantumCircuit, ControlFlowOp
from qiskit.transpiler import Target
from qiskit.providers.backend import BackendV1, BackendV2
from .deprecation import deprecate_function


def is_simulator(backend: BackendV1 | BackendV2) -> bool:
Expand Down Expand Up @@ -157,7 +158,20 @@ def is_crn(locator: str) -> bool:
return isinstance(locator, str) and locator.startswith("crn:")


def get_runtime_api_base_url(url: str, instance: str, private_endpoint: bool = False) -> str:
@deprecate_function(
"get_runtime_api_base_url()",
"0.30.0",
"Please use default_runtime_url_resolver() instead.",
stacklevel=1,
)
def get_runtime_api_base_url(
url: str, instance: str, private_endpoint: Optional[bool] = False
) -> str:
"""Computes the Runtime API base URL based on the provided input parameters."""
return default_runtime_url_resolver(url, instance, private_endpoint=private_endpoint)


def default_runtime_url_resolver(url: str, instance: str, private_endpoint: bool = False) -> str:
"""Computes the Runtime API base URL based on the provided input parameters.
Args:
Expand Down
1 change: 1 addition & 0 deletions release-notes/unreleased/1914.deprecation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecate util function `get_runtime_api_base_url`: use `default_runtime_url_resolver` instead.
14 changes: 14 additions & 0 deletions release-notes/unreleased/1914.feat.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Add `url_resolver` optional input to :class:`.QiskitRuntimeService`
constructor to enable custom generation of the Qiskit Runtime API URL
based on the provided `url`, `instance` and `private_endpoint`. If
not specified, the default resolver will be used.

.. code:: python
# Define a custom resolver. In this case returns the concatenation of the provided `url` and the `instance`
def custom_url_resolver(url, instance, *args, **kwargs):
return f"{url}/{instance}"
service = QiskitRuntimeService(channel="ibm_quantum", instance="ibm-q/open/main", url="https://baseurl.org" url_resolver=custom_url_resolver)
# resulting resolved url will be: `https://baseurl.org/ibm-q/open/main`
Add util function `default_runtime_url_resolver`.
27 changes: 25 additions & 2 deletions test/unit/test_client_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,31 +57,52 @@ def test_get_runtime_api_base_url(self) -> None:
"ibm_cloud",
"crn:v1:bluemix:public:quantum-computing:us-east:a/...:...::",
"https://cloud.ibm.com",
None,
"https://us-east.quantum-computing.cloud.ibm.com",
),
(
"ibm_cloud",
"crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::",
"https://cloud.ibm.com",
None,
"https://my-region.quantum-computing.cloud.ibm.com",
),
(
"ibm_cloud",
"crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::",
"https://api-ntc-name.experimental-us-someid.us-east.containers.appdomain.cloud",
None,
"https://api-ntc-name.experimental-us-someid.us-east.containers.appdomain.cloud",
),
(
"ibm_quantum",
"h/g/p",
"https://auth.quantum-computing.ibm.com/api",
None,
"https://auth.quantum-computing.ibm.com/api",
),
(
"ibm_cloud",
"crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::",
"https://api-ntc-name.experimental-us-someid.us-east.containers.appdomain.cloud",
lambda a, b, c: f"{a}:{b}:{c}",
"https://api-ntc-name.experimental-us-someid.us-east.containers.appdomain.cloud:"
+ "crn:v1:bluemix:public:quantum-computing:my-region:a/...:...:::False",
),
(
"ibm_quantum",
"h/g/p",
"https://auth.quantum-computing.ibm.com/api",
lambda a, b, c: f"{a}:{b}:{c}",
"https://auth.quantum-computing.ibm.com/api:h/g/p:False",
),
]
for spec in test_specs:
channel, instance, url, expected = spec
channel, instance, url, url_resolver, expected = spec
with self.subTest(instance=instance, url=url):
params = self._get_client_params(channel=channel, instance=instance, url=url)
params = self._get_client_params(
channel=channel, instance=instance, url=url, url_resolver=url_resolver
)
self.assertEqual(params.get_runtime_api_base_url(), expected)

def test_proxies_param_with_ntlm(self) -> None:
Expand Down Expand Up @@ -153,6 +174,7 @@ def _get_client_params(
instance=None,
proxies=None,
verify=None,
url_resolver=None,
):
"""Return a custom ClientParameters."""
if verify is None:
Expand All @@ -164,4 +186,5 @@ def _get_client_params(
instance=instance,
proxies=proxies,
verify=verify,
url_resolver=url_resolver,
)

0 comments on commit 0754905

Please sign in to comment.