Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ Most of the code in `ionq_core/` is **auto-generated** from the IonQ OpenAPI spe
**Hand-written (edit freely):**
- `ionq_core/__init__.py` -- public API exports
- `ionq_core/ionq_client.py` -- IonQClient convenience wrapper
- `ionq_core/_exceptions.py` -- exception hierarchy
- `ionq_core/_extensions.py` -- extension API for downstream SDKs
- `ionq_core/_transport.py` -- retry transport
- `ionq_core/_pagination.py` -- pagination helpers
- `ionq_core/_polling.py` -- job polling helpers
- `ionq_core/exceptions.py` -- exception hierarchy
- `ionq_core/extensions.py` -- extension API for downstream SDKs
- `ionq_core/_transport.py` -- retry transport (internal)
- `ionq_core/pagination.py` -- pagination helpers
- `ionq_core/polling.py` -- job polling helpers
- `ionq_core/gates.py` -- native gate matrices
- `ionq_core/session.py` -- session lifecycle manager
- `tests/` -- all tests

## Regenerating the client
Expand Down Expand Up @@ -65,6 +67,10 @@ uvx openapi-python-client==0.28.3 generate \
- CI must pass before merging (lint, tests, type check, generated code staleness check).
- The generated code staleness check on PRs verifies that `ionq_core/` matches what the generator produces. If it fails, regenerate and commit the result.

## Contributor License Agreement

To receive IonQ's CLA, please contact @mjk or email [opensource@ionq.com](mailto:opensource@ionq.com).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mjk fyi


## License

By submitting a pull request, you represent that you have the right to license your
Expand Down
12 changes: 6 additions & 6 deletions custom-templates/package_init.py.jinja
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% from "helpers.jinja" import safe_docstring %}
{{ safe_docstring(package_description) }}
from ._exceptions import (
from .exceptions import (
APIConnectionError,
APIError,
APITimeoutError,
Expand All @@ -12,16 +12,16 @@ from ._exceptions import (
RateLimitError,
ServerError,
)
from ._extensions import AsyncEventHook, ClientExtension, EventHook
from ._gates import gpi2_matrix, gpi_matrix, ms_matrix, zz_matrix
from ._pagination import aiter_jobs, aiter_session_jobs, iter_jobs, iter_session_jobs
from ._polling import (
from .extensions import AsyncEventHook, ClientExtension, EventHook
from .gates import gpi2_matrix, gpi_matrix, ms_matrix, zz_matrix
from .pagination import aiter_jobs, aiter_session_jobs, iter_jobs, iter_session_jobs
from .polling import (
JobFailedError,
JobTimeoutError,
async_wait_for_job,
wait_for_job,
)
from ._session import SessionManager
from .session import SessionManager
from .client import AuthenticatedClient, Client
from .ionq_client import IonQClient, __version__
from .types import UNSET, Unset
Expand Down
16 changes: 8 additions & 8 deletions ionq_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

"""A client library for accessing IonQ Cloud Platform API"""

from ._exceptions import (
from .client import AuthenticatedClient, Client
from .exceptions import (
APIConnectionError,
APIError,
APITimeoutError,
Expand All @@ -15,18 +16,17 @@
RateLimitError,
ServerError,
)
from ._extensions import AsyncEventHook, ClientExtension, EventHook
from ._gates import gpi2_matrix, gpi_matrix, ms_matrix, zz_matrix
from ._pagination import aiter_jobs, aiter_session_jobs, iter_jobs, iter_session_jobs
from ._polling import (
from .extensions import AsyncEventHook, ClientExtension, EventHook
from .gates import gpi2_matrix, gpi_matrix, ms_matrix, zz_matrix
from .ionq_client import IonQClient, __version__
from .pagination import aiter_jobs, aiter_session_jobs, iter_jobs, iter_session_jobs
from .polling import (
JobFailedError,
JobTimeoutError,
async_wait_for_job,
wait_for_job,
)
from ._session import SessionManager
from .client import AuthenticatedClient, Client
from .ionq_client import IonQClient, __version__
from .session import SessionManager
from .types import UNSET, Unset

__all__ = (
Expand Down
2 changes: 1 addition & 1 deletion ionq_core/_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import httpx
from httpx_retries import Retry, RetryTransport

from ._exceptions import APIConnectionError, APITimeoutError, raise_for_status
from .exceptions import APIConnectionError, APITimeoutError, raise_for_status

RETRYABLE_STATUS_CODES: frozenset[int] = frozenset({429, 500, 502, 503, *range(520, 530)})
"""HTTP status codes that trigger an automatic retry."""
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion ionq_core/ionq_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

import httpx

from ._extensions import ClientExtension, HookTransport
from ._transport import DEFAULT_MAX_RETRIES, RETRYABLE_STATUS_CODES, build_transport
from .client import AuthenticatedClient
from .extensions import ClientExtension, HookTransport

try:
__version__ = _pkg_version("ionq-core")
Expand Down
2 changes: 1 addition & 1 deletion ionq_core/_pagination.py → ionq_core/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
from collections.abc import AsyncIterator, Callable, Iterator
from typing import TYPE_CHECKING, Any

from ._exceptions import IonQError
from .api.default import get_jobs, get_session_jobs
from .exceptions import IonQError
from .types import UNSET, Unset

if TYPE_CHECKING:
Expand Down
2 changes: 1 addition & 1 deletion ionq_core/_polling.py → ionq_core/polling.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
import time
from typing import TYPE_CHECKING

from ._exceptions import IonQError
from .api.default import get_job
from .exceptions import IonQError
from .types import Unset

if TYPE_CHECKING:
Expand Down
2 changes: 1 addition & 1 deletion ionq_core/_session.py → ionq_core/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
import logging
from typing import TYPE_CHECKING

from ._exceptions import IonQError
from .api.default import create_session, end_session, get_session
from .exceptions import IonQError
from .models.create_session_request import CreateSessionRequest
from .models.session_cost_limit import SessionCostLimit
from .models.session_settings_request import SessionSettingsRequest
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import pytest

from ionq_core import SessionManager
from ionq_core._exceptions import NotFoundError
from ionq_core.api.default import get_session_jobs, get_sessions
from ionq_core.exceptions import NotFoundError

pytestmark = pytest.mark.integration

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import pytest

from ionq_core._exceptions import PermissionDeniedError
from ionq_core.api.usage import get_usages
from ionq_core.exceptions import PermissionDeniedError

pytestmark = pytest.mark.integration

Expand Down
2 changes: 1 addition & 1 deletion tests/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from ionq_core._exceptions import (
from ionq_core.exceptions import (
APIError,
AuthenticationError,
BadRequestError,
Expand Down
6 changes: 3 additions & 3 deletions tests/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import pytest

from ionq_core import ClientExtension, EventHook, IonQClient
from ionq_core._exceptions import APIError, NotFoundError
from ionq_core._extensions import (
from ionq_core._transport import ErrorRaisingTransport
from ionq_core.exceptions import APIError, NotFoundError
from ionq_core.extensions import (
AsyncEventHook,
HookTransport,
)
from ionq_core._transport import ErrorRaisingTransport

_BACKENDS_URL = "https://api.ionq.co/v0.4/backends"

Expand Down
2 changes: 1 addition & 1 deletion tests/test_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from ionq_core._gates import gpi2_matrix, gpi_matrix, ms_matrix, zz_matrix
from ionq_core.gates import gpi2_matrix, gpi_matrix, ms_matrix, zz_matrix

_PHIS = [0, 0.1, 0.25, 0.5, 0.73]

Expand Down
12 changes: 6 additions & 6 deletions tests/test_polling.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import pytest

from ionq_core._exceptions import IonQError
from ionq_core._polling import JobFailedError, JobTimeoutError, async_wait_for_job, wait_for_job
from ionq_core.exceptions import IonQError
from ionq_core.polling import JobFailedError, JobTimeoutError, async_wait_for_job, wait_for_job
from tests.conftest import make_job_json

_real_sleep = asyncio.sleep
Expand All @@ -17,7 +17,7 @@ def test_already_completed(self, httpx_mock, auth_client):
assert wait_for_job(auth_client, "j1", timeout=5).status == "completed"

def test_polls_until_completed(self, httpx_mock, auth_client, monkeypatch):
monkeypatch.setattr("ionq_core._polling.time.sleep", lambda _: None)
monkeypatch.setattr("ionq_core.polling.time.sleep", lambda _: None)
for s in ("submitted", "ready", "completed"):
httpx_mock.add_response(json=make_job_json("j1", s))
assert wait_for_job(auth_client, "j1", poll_interval=0.01, timeout=10).status == "completed"
Expand All @@ -42,7 +42,7 @@ def test_none_response_raises(self, httpx_mock, auth_client):
wait_for_job(auth_client, "j1", timeout=5)

def test_timeout_raises(self, httpx_mock, auth_client, monkeypatch):
monkeypatch.setattr("ionq_core._polling.time.sleep", lambda _: None)
monkeypatch.setattr("ionq_core.polling.time.sleep", lambda _: None)
httpx_mock.add_response(json=make_job_json("j1", "submitted"), is_reusable=True)
with pytest.raises(JobTimeoutError, match="j1"):
wait_for_job(auth_client, "j1", poll_interval=0.01, timeout=0.0)
Expand All @@ -69,13 +69,13 @@ async def test_none_response_raises(self, httpx_mock, auth_client):
await async_wait_for_job(auth_client, "j1", timeout=5)

async def test_timeout_raises(self, httpx_mock, auth_client, monkeypatch):
monkeypatch.setattr("ionq_core._polling.asyncio.sleep", lambda _: _real_sleep(0))
monkeypatch.setattr("ionq_core.polling.asyncio.sleep", lambda _: _real_sleep(0))
httpx_mock.add_response(json=make_job_json("j1", "submitted"), is_reusable=True)
with pytest.raises(JobTimeoutError, match="j1"):
await async_wait_for_job(auth_client, "j1", poll_interval=0.01, timeout=0.0)

async def test_polls_until_completed(self, httpx_mock, auth_client, monkeypatch):
monkeypatch.setattr("ionq_core._polling.asyncio.sleep", lambda _: _real_sleep(0))
monkeypatch.setattr("ionq_core.polling.asyncio.sleep", lambda _: _real_sleep(0))
for s in ("submitted", "ready", "completed"):
httpx_mock.add_response(json=make_job_json("j1", s))
result = await async_wait_for_job(auth_client, "j1", poll_interval=0.01, timeout=10)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import httpx
import pytest

from ionq_core._exceptions import IonQError
from ionq_core._session import SessionManager
from ionq_core.exceptions import IonQError
from ionq_core.session import SessionManager

_BASE = "https://test.invalid/v0.4"

Expand Down
4 changes: 2 additions & 2 deletions tests/test_transport.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import httpx
import pytest

from ionq_core._exceptions import (
from ionq_core._transport import ErrorRaisingTransport, build_transport
from ionq_core.exceptions import (
APIConnectionError,
APITimeoutError,
AuthenticationError,
Expand All @@ -10,7 +11,6 @@
RateLimitError,
ServerError,
)
from ionq_core._transport import ErrorRaisingTransport, build_transport

_URL = "https://api.ionq.co/v0.4/backends"

Expand Down
Loading