diff --git a/.travis.yml b/.travis.yml index 97425d1c9..1c522e629 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,7 +45,7 @@ stage_linux: &stage_linux <<: *stage_generic os: linux language: python - python: 3.5 + python: 3.6 stage_osx: &stage_osx <<: *stage_generic @@ -82,9 +82,6 @@ stage_win: &stage_win | export PATH="/c/Python${PYTHON_VERSION}:/c/Python${PYTHON_VERSION}/Scripts:${PATH}" case $PYTHON_VERSION in - 35) - choco install python --version 3.5.4 - ;; 36) choco install python --version 3.6.5 ;; @@ -115,7 +112,7 @@ jobs: include: # "lint and and pure python test" stage ########################################################################### - # Linter and style check (GNU/Linux, Python 3.5) + # Linter and style check (GNU/Linux, Python 3.7) - stage: lint and pure python test <<: *stage_linux if: type != cron @@ -129,7 +126,7 @@ jobs: if: type != cron script: make mypy - # Run the tests against without compilation (GNU/Linux, Python 3.5) + # Run the tests against without compilation (GNU/Linux, Python 3.6) - stage: lint and pure python test <<: *stage_linux if: type != cron @@ -156,14 +153,6 @@ jobs: dist: xenial python: 3.8 - # OSX, Python 3.5.6 (via pyenv) - - stage: test - <<: *stage_osx - if: type != cron - env: - - MPLBACKEND=ps - - PYTHON_VERSION=3.5.6 - # OSX, Python 3.6.5 (via pyenv) - stage: test <<: *stage_osx @@ -228,11 +217,6 @@ jobs: <<: *stage_win env: - PYTHON_VERSION=36 - # Windows, Python 3.5 - - if: type = cron - <<: *stage_win - env: - - PYTHON_VERSION=35 - if: tag IS present language: python python: "3.6" diff --git a/Makefile b/Makefile index 2607e4449..86fbb93bc 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ lint: pylint -rn qiskit/providers/ibmq test mypy: - mypy --module qiskit.providers.ibmq --show-error-codes + mypy --module qiskit.providers.ibmq --show-error-codes --no-site-packages style: pycodestyle qiskit test diff --git a/azure-pipelines.yml b/azure-pipelines.yml index eb73b56ea..6c238f0d9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,8 +12,6 @@ jobs: pool: {vmImage: 'vs2017-win2016'} strategy: matrix: - Python35: - python.version: '3.5' Python36: python.version: '3.6' Python37: @@ -42,10 +40,8 @@ jobs: condition: eq(variables['Build.Reason'], 'Schedule') strategy: matrix: - Python35: - python.version: '3.5' -# Python36: -# python.version: '3.6' + Python36: + python.version: '3.6' # Python37: # python.version: '3.7' steps: diff --git a/qiskit/providers/ibmq/api/clients/account.py b/qiskit/providers/ibmq/api/clients/account.py index e60301ddc..a5fc769b4 100644 --- a/qiskit/providers/ibmq/api/clients/account.py +++ b/qiskit/providers/ibmq/api/clients/account.py @@ -19,8 +19,7 @@ import time from typing import List, Dict, Any, Optional, Union -# Disabled unused-import because datetime is used only for type hints. -from datetime import datetime # pylint: disable=unused-import +from datetime import datetime from qiskit.providers.ibmq.apiconstants import (API_JOB_FINAL_STATES, ApiJobStatus, ApiJobShareLevel) diff --git a/qiskit/providers/ibmq/api/clients/auth.py b/qiskit/providers/ibmq/api/clients/auth.py index 4d9f1afcd..ed49fbe1e 100644 --- a/qiskit/providers/ibmq/api/clients/auth.py +++ b/qiskit/providers/ibmq/api/clients/auth.py @@ -14,7 +14,7 @@ """Client for accessing IBM Quantum Experience authentication services.""" -from typing import Dict, List, Optional, Any +from typing import Dict, List, Optional, Any, Union from requests.exceptions import RequestException from ..exceptions import AuthenticationLicenseError, RequestsApiError @@ -141,7 +141,7 @@ def user_hubs(self) -> List[Dict[str, str]]: # Miscellaneous public functions. - def api_version(self) -> Dict[str, str]: + def api_version(self) -> Dict[str, Union[str, bool]]: """Return the version of the API. Returns: diff --git a/qiskit/providers/ibmq/api/clients/websocket.py b/qiskit/providers/ibmq/api/clients/websocket.py index fc0385a6e..193f6e899 100644 --- a/qiskit/providers/ibmq/api/clients/websocket.py +++ b/qiskit/providers/ibmq/api/clients/websocket.py @@ -20,10 +20,9 @@ import logging import time from abc import ABC, abstractmethod -from typing import Dict, Union, Generator, Optional, Any +from typing import Dict, Union, Optional, Any from concurrent import futures from ssl import SSLError -import warnings import nest_asyncio from websockets import connect, ConnectionClosed @@ -57,10 +56,6 @@ except RuntimeError: LOOP = asyncio.new_event_loop() nest_asyncio.apply(LOOP) -# TODO Replace coroutine with async def once Python 3.5 is dropped. -# Also can upgrade to websocket 8 to avoid other deprecation warning. -warnings.filterwarnings("ignore", category=DeprecationWarning, - message="\"@coroutine\" decorator is deprecated") class WebsocketMessage(ABC): @@ -151,8 +146,7 @@ def __init__(self, websocket_url: str, access_token: str) -> None: self.websocket_url = websocket_url.rstrip('/') self.access_token = access_token - @asyncio.coroutine - def _connect(self, url: str) -> Generator[Any, None, WebSocketClientProtocol]: + async def _connect(self, url: str) -> WebSocketClientProtocol: """Authenticate with the websocket server and return the connection. Returns: @@ -168,10 +162,7 @@ def _connect(self, url: str) -> Generator[Any, None, WebSocketClientProtocol]: """ try: logger.debug('Starting new websocket connection: %s', url) - with warnings.catch_warnings(): - # Suppress websockets deprecation warnings until the fix is available - warnings.filterwarnings("ignore", category=DeprecationWarning) - websocket = yield from connect(url) + websocket = await connect(url) # Isolate specific exceptions, so they are not retried in `get_job_status`. except (SSLError, InvalidURI) as ex: @@ -188,21 +179,19 @@ def _connect(self, url: str) -> Generator[Any, None, WebSocketClientProtocol]: try: # Authenticate against the server. auth_request = self._authentication_message() - with warnings.catch_warnings(): - # Suppress websockets deprecation warnings until the fix is available - warnings.filterwarnings("ignore", category=DeprecationWarning) - yield from websocket.send(auth_request.as_json()) + await websocket.send(auth_request.as_json()) - # Verify that the server acknowledged our authentication. - auth_response_raw = yield from websocket.recv() + # Verify that the server acknowledged our authentication. + auth_response_raw = await websocket.recv() - auth_response = WebsocketResponseMethod.from_bytes(auth_response_raw) + auth_response = WebsocketResponseMethod.from_bytes( + auth_response_raw) # type: ignore[arg-type] if auth_response.type_ != 'authenticated': raise WebsocketIBMQProtocolError('Failed to authenticate against the server: {}' .format(auth_response.as_json())) except ConnectionClosed as ex: - yield from websocket.close() + await websocket.close() exception_to_raise = WebsocketAuthenticationError( 'Unexpected error occurred when authenticating against the server.') @@ -212,15 +201,14 @@ def _connect(self, url: str) -> Generator[Any, None, WebSocketClientProtocol]: return websocket - @asyncio.coroutine - def get_job_status( + async def get_job_status( self, job_id: str, timeout: Optional[float] = None, retries: int = 5, backoff_factor: float = 0.5, status_queue: Optional[RefreshQueue] = None - ) -> Generator[Any, None, Dict[str, str]]: + ) -> Dict[str, str]: """Return the status of a job. Read status messages from the server, which are issued at regular @@ -269,24 +257,22 @@ def get_job_status( while current_retry_attempt <= retries: try: - websocket = yield from self._connect(url) + websocket = await self._connect(url) # Read messages from the server until the connection is closed or # a timeout has been reached. while True: try: - with warnings.catch_warnings(): - # Suppress websockets deprecation warnings until the fix is available - warnings.filterwarnings("ignore", category=DeprecationWarning) - if timeout: - response_raw = yield from asyncio.wait_for( - websocket.recv(), timeout=timeout) - - # Decrease the timeout. - timeout = original_timeout - (time.time() - start_time) - else: - response_raw = yield from websocket.recv() - - response = WebsocketResponseMethod.from_bytes(response_raw) + if timeout: + response_raw = await asyncio.wait_for( + websocket.recv(), timeout=timeout) + + # Decrease the timeout. + timeout = original_timeout - (time.time() - start_time) + else: + response_raw = await websocket.recv() + + response = WebsocketResponseMethod.from_bytes( + response_raw) # type: ignore[arg-type] if logger.getEffectiveLevel() is logging.DEBUG: logger.debug('Received message from websocket: %s', filter_data(response.get_data())) @@ -356,16 +342,13 @@ def get_job_status( backoff_time = self._backoff_time(backoff_factor, current_retry_attempt) logger.info('Retrying get_job_status via websocket after %s seconds: ' 'Attempt #%s', backoff_time, current_retry_attempt) - yield from asyncio.sleep(backoff_time) # Block asyncio loop for given backoff time. + await asyncio.sleep(backoff_time) # Block asyncio loop for given backoff time. continue # Continues next iteration after `finally` block. finally: - with warnings.catch_warnings(): - # Suppress websockets deprecation warnings until the fix is available - warnings.filterwarnings("ignore", category=DeprecationWarning) - if websocket is not None: - yield from websocket.close() + if websocket is not None: + await websocket.close() # Execution should not reach here, sanity check. exception_message = 'Max retries exceeded: Failed to establish a websocket ' \ diff --git a/qiskit/providers/ibmq/api/rest/backend.py b/qiskit/providers/ibmq/api/rest/backend.py index 3629f8392..1d6215305 100644 --- a/qiskit/providers/ibmq/api/rest/backend.py +++ b/qiskit/providers/ibmq/api/rest/backend.py @@ -16,7 +16,7 @@ import json from typing import Dict, Optional, Any, List -from datetime import datetime # pylint: disable=unused-import +from datetime import datetime from .base import RestAdapterBase from ..session import RetrySession diff --git a/qiskit/providers/ibmq/backendjoblimit.py b/qiskit/providers/ibmq/backendjoblimit.py index ea0dfcfb5..850e8d2b6 100644 --- a/qiskit/providers/ibmq/backendjoblimit.py +++ b/qiskit/providers/ibmq/backendjoblimit.py @@ -14,7 +14,7 @@ """Job limit information related to a backend.""" -from typing import Any +from typing import Any, Dict class BackendJobLimit: @@ -31,7 +31,7 @@ class BackendJobLimit: this provider. """ - _data = {} + _data = {} # type:Dict def __init__(self, maximum_jobs: int, running_jobs: int, **kwargs: Any) -> None: """BackendJobLimit constructor. diff --git a/qiskit/providers/ibmq/backendreservation.py b/qiskit/providers/ibmq/backendreservation.py index 56fcbcba9..70170de05 100644 --- a/qiskit/providers/ibmq/backendreservation.py +++ b/qiskit/providers/ibmq/backendreservation.py @@ -14,7 +14,7 @@ """Reservation information related to a backend.""" -from typing import Optional +from typing import Optional, Any from datetime import datetime @@ -87,7 +87,7 @@ def __repr__(self) -> str: out_str += ')>' return out_str - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: if isinstance(other, BackendReservation) and self.backend_name == other.backend_name: if self.reservation_id and self.reservation_id == other.reservation_id: return True diff --git a/qiskit/providers/ibmq/ibmqbackendservice.py b/qiskit/providers/ibmq/ibmqbackendservice.py index e356c9d51..37126c8a7 100644 --- a/qiskit/providers/ibmq/ibmqbackendservice.py +++ b/qiskit/providers/ibmq/ibmqbackendservice.py @@ -21,7 +21,8 @@ from typing import Dict, List, Callable, Optional, Any, Union from datetime import datetime -from qiskit.providers import JobStatus, QiskitBackendNotFoundError # type: ignore[attr-defined] +from qiskit.providers.jobstatus import JobStatus +from qiskit.providers.exceptions import QiskitBackendNotFoundError from qiskit.providers.providerutils import filter_backends from qiskit.providers.ibmq import accountprovider # pylint: disable=unused-import @@ -359,13 +360,13 @@ def _update_creation_date_filter( lt_list.append(cur_dt_filter.pop('between')[1]) lte_dt = min(lt_list) if lt_list else None - new_dt_filter = {} + new_dt_filter = {} # type: Dict[str, Union[str, List[str]]] if gte_dt and lte_dt: new_dt_filter['between'] = [gte_dt, lte_dt] elif gte_dt: - new_dt_filter['gte'] = gte_dt # type: ignore[assignment] + new_dt_filter['gte'] = gte_dt elif lte_dt: - new_dt_filter['lte'] = lte_dt # type: ignore[assignment] + new_dt_filter['lte'] = lte_dt return new_dt_filter @@ -431,7 +432,7 @@ def _get_status_filter(self, status: Union[JobStatus, str]) -> Dict[str, Any]: elif status == JobStatus.DONE: _status_filter = {'status': ApiJobStatus.COMPLETED.value} elif status == JobStatus.ERROR: - _status_filter = {'status': {'regexp': '^ERROR'}} # type: ignore[assignment] + _status_filter = {'status': {'regexp': '^ERROR'}} else: raise IBMQBackendValueError( '"{}" is not a valid status value. Valid values are {}'.format( diff --git a/qiskit/providers/ibmq/job/ibmqjob.py b/qiskit/providers/ibmq/job/ibmqjob.py index d5c1fd752..11c735c9f 100644 --- a/qiskit/providers/ibmq/job/ibmqjob.py +++ b/qiskit/providers/ibmq/job/ibmqjob.py @@ -97,7 +97,7 @@ class IBMQJob(BaseJob): which is a supported attribute. """ - _data = {} + _data = {} # type: Dict _executor = futures.ThreadPoolExecutor() """Threads used for asynchronous processing.""" @@ -890,7 +890,7 @@ def _wait_for_completion( return self._status in required_status - def _retrieve_result(self, refresh: bool = False): + def _retrieve_result(self, refresh: bool = False) -> None: """Retrieve the job result response. Args: diff --git a/qiskit/providers/ibmq/job/queueinfo.py b/qiskit/providers/ibmq/job/queueinfo.py index 6f7d21497..8bc6efaae 100644 --- a/qiskit/providers/ibmq/job/queueinfo.py +++ b/qiskit/providers/ibmq/job/queueinfo.py @@ -14,7 +14,7 @@ """Queue information for a job.""" -from typing import Any, Optional, Union +from typing import Any, Optional, Union, Dict from datetime import datetime import warnings @@ -27,7 +27,7 @@ class QueueInfo: """Queue information for a job.""" - _data = {} + _data = {} # type: Dict def __init__( self, diff --git a/qiskit/providers/ibmq/managed/managedresults.py b/qiskit/providers/ibmq/managed/managedresults.py index a22a5a878..207548be6 100644 --- a/qiskit/providers/ibmq/managed/managedresults.py +++ b/qiskit/providers/ibmq/managed/managedresults.py @@ -17,7 +17,6 @@ from typing import List, Optional, Union, Tuple, Dict import copy -# TODO Use TYPE_CHECKING instead of pylint disable after dropping python 3.5 import numpy # pylint: disable=unused-import from qiskit.result import Result from qiskit.circuit import QuantumCircuit @@ -57,7 +56,7 @@ def __init__( self._job_set = job_set self.backend_name = backend_name self.success = success - self._combined_results = None # type: Result + self._combined_results = None # type: Optional[Result] def data(self, experiment: Union[str, QuantumCircuit, Schedule, int]) -> Dict: """Get the raw data for an experiment. diff --git a/qiskit/providers/ibmq/managed/utils.py b/qiskit/providers/ibmq/managed/utils.py index 58b29e8b8..cfbe57112 100644 --- a/qiskit/providers/ibmq/managed/utils.py +++ b/qiskit/providers/ibmq/managed/utils.py @@ -58,7 +58,7 @@ def _wrapper( return value of the decorated function. """ futures = [managed_job.future for managed_job - in job_set._managed_jobs if managed_job.future] + in job_set._managed_jobs if managed_job.future] # type: ignore[unreachable] wait(futures) return func(job_set, *args, **kwargs) diff --git a/qiskit/providers/ibmq/random/baserandomservice.py b/qiskit/providers/ibmq/random/baserandomservice.py index 0d825ccd7..08d9e9312 100644 --- a/qiskit/providers/ibmq/random/baserandomservice.py +++ b/qiskit/providers/ibmq/random/baserandomservice.py @@ -15,7 +15,7 @@ """Module for interfacing with a remote extractor.""" import logging -from typing import List +from typing import List, Any from abc import ABC, abstractmethod @@ -49,6 +49,6 @@ def __init__( self.methods = methods @abstractmethod - def run(self, *args, **kwargs): + def run(self, *args: Any, **kwargs: Any) -> Any: """Execute the service.""" pass diff --git a/qiskit/providers/ibmq/random/cqcextractor.py b/qiskit/providers/ibmq/random/cqcextractor.py index f25ba4ed8..bd309f836 100644 --- a/qiskit/providers/ibmq/random/cqcextractor.py +++ b/qiskit/providers/ibmq/random/cqcextractor.py @@ -47,7 +47,7 @@ class CQCExtractor(BaseRandomService): output of extractor 1 as its seed, so it must wait for extractor 1 to finish first. """ - def run( + def run( # type: ignore[override] self, ext1_input_num_bits: int, ext1_output_num_bits: int, @@ -55,7 +55,8 @@ def run( ext1_wsr_bytes: bytes, ext2_seed_num_bits: int, ext2_wsr_multiplier: int, - ext2_wsr_generator: Optional[Callable] = None) -> List[int]: + ext2_wsr_generator: Optional[Callable] = None + ) -> List[int]: """Process input data synchronously. Args: @@ -158,7 +159,7 @@ def run_async_ext2( "ext2_wsr_multiplier must be non-zero.") logger.info("Starting second extraction.") - ext2_seed = bitarray_to_bytes(ext2_seed[:ext2_seed_num_bits]) + ext2_seed = bitarray_to_bytes(ext2_seed[:ext2_seed_num_bits]) # type: ignore[assignment] if ext2_wsr_generator is None: ext2_wsr_generator = generate_wsr ext2_wsr = ext2_wsr_generator(ext2_seed_num_bits*ext2_wsr_multiplier) @@ -186,7 +187,7 @@ def retrieve_job(self, job_id: str) -> CQCExtractorJob: """ return CQCExtractorJob(job_id, self._client) - def __repr__(self): + def __repr__(self) -> str: return "<{}('{}') from {}>".format(self.__class__.__name__, self.name, self._provider) diff --git a/qiskit/providers/ibmq/random/ibmqrandomservice.py b/qiskit/providers/ibmq/random/ibmqrandomservice.py index 8695fefca..54e84c076 100644 --- a/qiskit/providers/ibmq/random/ibmqrandomservice.py +++ b/qiskit/providers/ibmq/random/ibmqrandomservice.py @@ -15,7 +15,7 @@ """IBMQ random number service.""" import logging -from typing import Dict, List +from typing import Dict, List, Any from qiskit.providers.ibmq import accountprovider # pylint: disable=unused-import from .baserandomservice import BaseRandomService @@ -105,11 +105,11 @@ def get_service(self, name: str) -> BaseRandomService: return service - def __dir__(self): + def __dir__(self) -> Dict: self._discover_services() return self.__dict__ - def __getattr__(self, item): + def __getattr__(self, item: str) -> Any: self._discover_services() try: return self._services[item] diff --git a/qiskit/providers/ibmq/version.py b/qiskit/providers/ibmq/version.py index a9cfdcafa..9cd1eb2fc 100644 --- a/qiskit/providers/ibmq/version.py +++ b/qiskit/providers/ibmq/version.py @@ -21,11 +21,12 @@ import os import subprocess +from typing import List ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -def _minimal_ext_cmd(cmd): +def _minimal_ext_cmd(cmd: List[str]) -> bytes: # construct minimal environment env = {} for k in ['SYSTEMROOT', 'PATH']: @@ -45,7 +46,7 @@ def _minimal_ext_cmd(cmd): return out -def git_version(): +def git_version() -> str: """Get the current git head sha1.""" # Determine if we're at master try: @@ -61,7 +62,7 @@ def git_version(): VERSION = version_file.read().strip() -def get_version_info(): +def get_version_info() -> str: """Get the full version string.""" # Adding the git rev number needs to be done inside # write_version_py(), otherwise the import of scipy.version messes diff --git a/releasenotes/notes/drop-py35-0eec8b799e9ae407.yaml b/releasenotes/notes/drop-py35-0eec8b799e9ae407.yaml new file mode 100644 index 000000000..692b95bef --- /dev/null +++ b/releasenotes/notes/drop-py35-0eec8b799e9ae407.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + The deprecated support for running qiskit-ibmq-provider with Python 3.5 has + been removed. To use qiskit-ibmq-provider >=0.11.0 you will now need at + least Python 3.6. If you are using Python 3.5 the last version which will + work is qiskit-ibmq-provider 0.10.x. diff --git a/releasenotes/notes/websockets-8-b02a2cdc133c2a25.yaml b/releasenotes/notes/websockets-8-b02a2cdc133c2a25.yaml new file mode 100644 index 000000000..cc140aaf8 --- /dev/null +++ b/releasenotes/notes/websockets-8-b02a2cdc133c2a25.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + Prior to this release, ``websockets`` 7.0 was used for Python 3.6. + With this release, ``websockets`` 8.0 or above is required for all Python versions. + The package requirements have been updated to reflect this. diff --git a/requirements-dev.txt b/requirements-dev.txt index e64f339ab..82bc69ced 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,9 +3,8 @@ pycodestyle pylint>=2.4 pylintfileheader>=0.0.2 vcrpy -pproxy==1.2.2; python_version <= '3.5' -pproxy==2.1.8; python_version > '3.5' -Sphinx>=1.8.3,<3.1.0 +pproxy==2.1.8 +Sphinx>=1.8.3 sphinx-rtd-theme>=0.4.0 sphinx-tabs>=1.1.11 sphinx-automodapi @@ -22,4 +21,4 @@ reno>=2.11.0 scipy>=1.0 nbformat>=4.4.0 nbconvert>=5.3.1 -qiskit_rng;python_version >= '3.6' \ No newline at end of file +qiskit_rng \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 17d0f8c45..435bd2f04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,7 @@ nest-asyncio>=1.0.0,!=1.1.0 qiskit-terra>=0.15 requests>=2.19 requests_ntlm>=1.1.0 -websockets>=7,<8;python_version <= '3.6' -websockets>=8;python_version > '3.6' +websockets>=8 numpy>=1.13 urllib3>=1.21.1 python-dateutil>=2.8.0 diff --git a/setup.py b/setup.py index d5aa84b85..ae7463878 100644 --- a/setup.py +++ b/setup.py @@ -21,8 +21,7 @@ "qiskit-terra>=0.15", "requests>=2.19", "requests-ntlm>=1.1.0", - "websockets>=7,<8;python_version <= '3.6'", - "websockets>=8;python_version > '3.6'", + "websockets>=8", "numpy>=1.13", "urllib3>=1.21.1", "python-dateutil>=2.8.0" @@ -61,7 +60,6 @@ "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", @@ -85,7 +83,7 @@ 'qiskit.providers.ibmq.experiment'], install_requires=REQUIREMENTS, include_package_data=True, - python_requires=">=3.5", + python_requires=">=3.6", zip_safe=False, extras_require={'visualization': ['matplotlib>=2.1', 'ipywidgets>=7.3.0', "seaborn>=0.9.0", "plotly>=4.4", diff --git a/test/ibmq/websocket/websocket_server.py b/test/ibmq/websocket/websocket_server.py index 0161d37c1..38dd1550d 100644 --- a/test/ibmq/websocket/websocket_server.py +++ b/test/ibmq/websocket/websocket_server.py @@ -16,7 +16,6 @@ import asyncio import json -import warnings from qiskit.providers.ibmq.api.clients.websocket import WebsocketResponseMethod @@ -30,12 +29,11 @@ TOKEN_WEBSOCKET_JOB_NOT_FOUND = 'token_websocket_job_not_found' -@asyncio.coroutine -def websocket_handler(websocket, path): +async def websocket_handler(websocket, path): """Entry point for the websocket mock server.""" # pylint: disable=unused-argument # Receive the authentication message. - msg_in = yield from websocket.recv() + msg_in = await websocket.recv() auth_message = json.loads(msg_in) # Check for valid access tokens. @@ -48,86 +46,77 @@ def websocket_handler(websocket, path): TOKEN_WEBSOCKET_RETRY_FAILURE, TOKEN_WEBSOCKET_JOB_NOT_FOUND): msg_out = json.dumps({'type': 'authenticated'}) - yield from websocket.send(msg_out.encode('utf8')) + await websocket.send(msg_out.encode('utf8')) else: # Close the connection. - yield from websocket.close() + await websocket.close() # Depending on the access token, perform different actions: if token == TOKEN_JOB_COMPLETED: - yield from handle_token_job_completed(websocket) + await handle_token_job_completed(websocket) elif token == TOKEN_JOB_TRANSITION: - yield from handle_token_job_transition(websocket) + await handle_token_job_transition(websocket) elif token == TOKEN_TIMEOUT: - yield from handle_token_timeout(websocket) + await handle_token_timeout(websocket) elif token == TOKEN_WRONG_FORMAT: - yield from handle_token_wrong_format(websocket) + await handle_token_wrong_format(websocket) elif token == TOKEN_WEBSOCKET_RETRY_SUCCESS: - yield from handle_token_retry_success(websocket) + await handle_token_retry_success(websocket) elif token == TOKEN_WEBSOCKET_RETRY_FAILURE: - yield from handle_token_retry_failure(websocket) + await handle_token_retry_failure(websocket) elif token == TOKEN_WEBSOCKET_JOB_NOT_FOUND: - yield from handle_token_job_not_found(websocket) + await handle_token_job_not_found(websocket) -@asyncio.coroutine -def handle_token_job_completed(websocket): +async def handle_token_job_completed(websocket): """Return a final job status, and close with 4002.""" msg_out = WebsocketResponseMethod(type_='job-status', data={'status': 'COMPLETED'}) - yield from websocket.send(msg_out.as_json().encode('utf8')) - yield from websocket.close(code=4002) + await websocket.send(msg_out.as_json().encode('utf8')) + await websocket.close(code=4002) -@asyncio.coroutine -def handle_token_job_transition(websocket): +async def handle_token_job_transition(websocket): """Send several job status, and close with 4002.""" msg_out = WebsocketResponseMethod(type_='job-status', data={'status': 'RUNNING'}) - yield from websocket.send(msg_out.as_json().encode('utf8')) + await websocket.send(msg_out.as_json().encode('utf8')) - yield from asyncio.sleep(1) + await asyncio.sleep(1) msg_out = WebsocketResponseMethod(type_='job-status', data={'status': 'COMPLETED'}) - yield from websocket.send(msg_out.as_json().encode('utf8')) + await websocket.send(msg_out.as_json().encode('utf8')) - yield from websocket.close(code=4002) + await websocket.close(code=4002) -@asyncio.coroutine -def handle_token_timeout(websocket): +async def handle_token_timeout(websocket): """Close the socket after 10 seconds, without replying.""" - yield from asyncio.sleep(10) - yield from websocket.close() + await asyncio.sleep(10) + await websocket.close() -@asyncio.coroutine -def handle_token_wrong_format(websocket): +async def handle_token_wrong_format(websocket): """Return a status in an invalid format.""" - yield from websocket.send('INVALID'.encode('utf8')) - yield from websocket.close() + await websocket.send('INVALID'.encode('utf8')) + await websocket.close() -@asyncio.coroutine -def handle_token_retry_success(websocket): +async def handle_token_retry_success(websocket): """Close the socket once and force a retry.""" if not hasattr(handle_token_retry_success, 'retry_attempt'): setattr(handle_token_retry_success, 'retry_attempt', True) - yield from handle_token_retry_failure(websocket) + await handle_token_retry_failure(websocket) else: - yield from handle_token_job_completed(websocket) + await handle_token_job_completed(websocket) -@asyncio.coroutine -def handle_token_retry_failure(websocket): +async def handle_token_retry_failure(websocket): """Continually close the socket, until both the first attempt and retry fail.""" - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) - yield from websocket.close() + await websocket.close() -@asyncio.coroutine -def handle_token_job_not_found(websocket): +async def handle_token_job_not_found(websocket): """Close the socket, specifying code for job not found.""" - yield from websocket.close(code=4003) + await websocket.close(code=4003) diff --git a/tox.ini b/tox.ini index 9397053df..526382ea4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.1 -envlist = py35, py36, py37, lint, docs +envlist = py36, py37, lint, docs skipsdist = True [testenv]