Skip to content

Commit

Permalink
Merge pull request #26 from qiboteam/raise_warning_on_version_mismatch
Browse files Browse the repository at this point in the history
Raise warning instead of error when qibo version mismatch
  • Loading branch information
scarrazza authored Feb 29, 2024
2 parents 9ed7542 + 4a5eac0 commit 83a850a
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 50 deletions.
5 changes: 4 additions & 1 deletion examples/run_successful_job.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import time

import qibo

from qibo_client import TII
Expand All @@ -14,6 +16,7 @@

# run the circuit
print(f"{'*'*20}\nPost first circuit")
start = time.time()
result = client.run_circuit(circuit, nshots=100, device="sim")

print(result)
print(f"Program done in {time.time() - start:.4f}s")
4 changes: 2 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ packages = [{ include = "qibo_client", from = "src" }]

[tool.poetry.dependencies]
python = ">=3.9,<3.12"
qibo = ">=0.2.2"
qibo = ">=0.2.4"
requests = "^2.31.0"

[tool.poetry.group.dev.dependencies]
Expand Down
8 changes: 8 additions & 0 deletions src/qibo_client/config_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import logging
import os

# configure logger
logging.basicConfig(format="[%(asctime)s] %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)
logging_level = os.environ.get("QIBO_CLIENT_LOGGER_LEVEL", logging.INFO)
logger.setLevel(logging_level)
9 changes: 9 additions & 0 deletions src/qibo_client/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import os
from pathlib import Path

MINIMUM_QIBO_VERSION_ALLOWED = "0.2.4"

RESULTS_BASE_FOLDER = Path(os.environ.get("RESULTS_BASE_FOLDER", "/tmp/qibo_client"))
SECONDS_BETWEEN_CHECKS = os.environ.get("SECONDS_BETWEEN_CHECKS", 2)

TIMEOUT = 10
57 changes: 27 additions & 30 deletions src/qibo_client/qibo_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""The module implementing the TIIProvider class."""

import logging
import os
import tarfile
import tempfile
import time
Expand All @@ -12,22 +10,9 @@
import qibo
import requests

from . import constants
from .config import JobPostServerError, MalformedResponseError

RESULTS_BASE_FOLDER = os.environ.get("RESULTS_BASE_FOLDER", "/tmp/qibo_client")
SECONDS_BETWEEN_CHECKS = os.environ.get("SECONDS_BETWEEN_CHECKS", 2)

RESULTS_BASE_FOLDER = Path(RESULTS_BASE_FOLDER)
RESULTS_BASE_FOLDER.mkdir(exist_ok=True)

TIMEOUT = 10


# configure logger
logging.basicConfig(format="[%(asctime)s] %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)
LOGGING_LEVEL = logging.INFO
logger.setLevel(LOGGING_LEVEL)
from .config_logging import logger


def wait_for_response_to_get_request(url: str) -> requests.models.Response:
Expand All @@ -40,9 +25,10 @@ def wait_for_response_to_get_request(url: str) -> requests.models.Response:
:rtype: requests.models.Response
"""
while True:
response = requests.get(url, timeout=TIMEOUT)
response = requests.get(url, timeout=constants.TIMEOUT)
# @TODO: change this !
if response.content == b"Job still in progress":
time.sleep(SECONDS_BETWEEN_CHECKS)
time.sleep(constants.SECONDS_BETWEEN_CHECKS)
continue
return response

Expand Down Expand Up @@ -135,18 +121,27 @@ def check_client_server_qibo_versions(self):
Raise assertion error if the two versions are not the same.
"""
qibo_local_version = qibo.__version__
msg = (
"The qibo-client package requires an installed qibo package version"
f">={constants.MINIMUM_QIBO_VERSION_ALLOWED}, the local qibo "
f"version is {qibo_local_version}"
)
assert qibo_local_version >= constants.MINIMUM_QIBO_VERSION_ALLOWED, msg

url = self.url + "qibo_version/"
response = requests.get(url, timeout=TIMEOUT)
response = requests.get(url, timeout=constants.TIMEOUT)
response.raise_for_status()
check_response_has_keys(response, ["qibo_version"])
qibo_server_version = response.json()["qibo_version"]
qibo_local_version = qibo.__version__

msg = (
"Local Qibo package version does not match the server one, please "
f"upgrade: {qibo_local_version} -> {qibo_server_version}"
)
assert qibo_local_version == qibo_server_version, msg
if qibo_local_version != qibo_server_version:
logger.warning(
"Local Qibo package version does not match the server one, please "
"upgrade: %s -> %s",
qibo_local_version,
qibo_server_version,
)

def run_circuit(
self, circuit: qibo.Circuit, nshots: int = 1000, device: str = "sim"
Expand Down Expand Up @@ -176,7 +171,9 @@ def run_circuit(

# retrieve results
logger.info("Job posted on server with pid %s", self.pid)
logger.info("Check results every %d seconds ...", SECONDS_BETWEEN_CHECKS)
logger.info(
"Check results every %d seconds ...", constants.SECONDS_BETWEEN_CHECKS
)
result = self._get_result()

return result
Expand All @@ -192,7 +189,7 @@ def _post_circuit(
"nshots": nshots,
"device": device,
}
response = requests.post(url, json=payload, timeout=TIMEOUT)
response = requests.post(url, json=payload, timeout=constants.TIMEOUT)

# checks
response.raise_for_status()
Expand All @@ -219,8 +216,8 @@ def _get_result(self) -> Optional[np.ndarray]:
response = wait_for_response_to_get_request(url)

# create the job results folder
self.results_folder = RESULTS_BASE_FOLDER / self.pid
self.results_folder.mkdir(exist_ok=True)
self.results_folder = constants.RESULTS_BASE_FOLDER / self.pid
self.results_folder.mkdir(parents=True, exist_ok=True)

# Save the stream to disk
try:
Expand Down
30 changes: 30 additions & 0 deletions tests/test_config_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from unittest import TestCase
from unittest.mock import patch

MOD = "qibo_client.config_logging"


def logging_wrap_function(logger_object):
logger_object.info("A debug log")
logger_object.error("An error log")


class TestLogger(TestCase):
@patch(f"{MOD}.os.environ", {"QIBO_CLIENT_LOGGER_LEVEL": "info"})
def test_logging_with_info_level(self, mock_os):
from qibo_client.config_logging import logger

with self.assertLogs() as captured:
logging_wrap_function(logger)
self.assertEqual(len(captured.records), 1)
self.assertEqual(captured.records[0].getMessage(), "An error log")

@patch(f"{MOD}.os.environ", {"QIBO_CLIENT_LOGGER_LEVEL": "notset"})
def test_logging_with_info_level(self):
from qibo_client.config_logging import logger

with self.assertLogs() as captured:
logging_wrap_function(logger)
self.assertEqual(len(captured.records), 2)
self.assertEqual(captured.records[0].getMessage(), "A debug log")
self.assertEqual(captured.records[1].getMessage(), "An error log")
32 changes: 16 additions & 16 deletions tests/test_qibo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

PKG = "qibo_client.qibo_client"
LOCAL_URL = "http://localhost:8000/"
FAKE_QIBO_VERSION = "0.0.1"
FAKE_QIBO_VERSION = "0.2.4"
FAKE_PID = "123"
ARCHIVE_NAME = "file.tar.gz"
TIMEOUT = 1
Expand All @@ -30,15 +30,15 @@ def mock_qibo():
@pytest.fixture(scope="module", autouse=True)
def mock_timeout():
"""Ensure that all the requests are made on localhost"""
with patch(f"{PKG}.TIMEOUT", TIMEOUT) as _fixture:
with patch(f"{PKG}.constants.TIMEOUT", TIMEOUT) as _fixture:
yield _fixture


@pytest.fixture
def results_base_folder(tmp_path: Path):
results_base_folder = tmp_path / "results"
results_base_folder.mkdir()
with patch(f"{PKG}.RESULTS_BASE_FOLDER", results_base_folder):
with patch(f"{PKG}.constants.RESULTS_BASE_FOLDER", results_base_folder):
yield results_base_folder


Expand Down Expand Up @@ -129,23 +129,23 @@ def test_check_client_server_qibo_versions_with_version_match(mock_request: Mock
)


def test_check_client_server_qibo_versions_with_version_mismatch(mock_request: Mock):
remote_qibo_version = "0.2.2"

def _new_side_effect(url, timeout):
return utils.MockedResponse(
status_code=200, json_data={"qibo_version": remote_qibo_version}
)
def test_check_client_server_qibo_versions_with_version_mismatch(
mock_qibo: Mock, mock_request: Mock
):
mock_qibo.__version__ = "0.2.1"
with (
patch(f"{PKG}.constants.MINIMUM_QIBO_VERSION_ALLOWED", "0.1.9"),
patch(f"{PKG}.logger") as mock_logger,
):
_get_tii_client()
mock_logger.warning.assert_called_once()

mock_request.get.side_effect = _new_side_effect

def test_check_client_server_qibo_versions_with_low_local_version(mock_qibo: Mock):
mock_qibo.__version__ = "0.0.1"
with pytest.raises(AssertionError):
_get_tii_client()

mock_request.get.assert_called_once_with(
LOCAL_URL + "qibo_version/", timeout=TIMEOUT
)


def test__post_circuit_with_invalid_token(mock_request: Mock):
def _new_side_effect(url, json, timeout):
Expand Down Expand Up @@ -194,7 +194,7 @@ def test_wait_for_response_to_get_request(mock_request: Mock):

mock_request.get.side_effect = [keep_waiting] * failed_attempts + [job_done]

with patch(f"{PKG}.SECONDS_BETWEEN_CHECKS", 1e-4):
with patch(f"{PKG}.constants.SECONDS_BETWEEN_CHECKS", 1e-4):
qibo_client.wait_for_response_to_get_request(url)

assert mock_request.get.call_count == failed_attempts + 1
Expand Down

0 comments on commit 83a850a

Please sign in to comment.