Rename `run_program` to just `run` (#580)

* update contributing with new arm64 setup

Signed-off-by: Paul S. Schweigert <paul@paulschweigert.com>

* refactor run_program method to run

Signed-off-by: Paul S. Schweigert <paul@paulschweigert.com>

* s/run/run_program/g for docs and notebooks

Signed-off-by: Paul S. Schweigert <paul@paulschweigert.com>

---------

Signed-off-by: Paul S. Schweigert <paul@paulschweigert.com>
This commit is contained in:
Paul Schweigert 2023-05-24 13:18:14 -04:00 committed by GitHub
parent f2de405a6e
commit 0bada3fea3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 178 additions and 20 deletions

View File

@ -134,7 +134,7 @@ If you wish to rebuild only a specific component (for example, the `gateway`), y
```docker-compose -f docker-compose-dev.yml build gateway``` ```docker-compose -f docker-compose-dev.yml build gateway```
For Apple Silicon system (arm64 / aarch64), use `docker-compose-dev-arm64.yml` instead of `docker-compose-dev.yml` For Apple Silicon system (arm64 / aarch64), set `TARGETARCH=arm64` before running the `docker-compose` command.
### Assigning yourself ### Assigning yourself

View File

@ -94,7 +94,7 @@ Full docs can be found at https://qiskit-extensions.github.io/quantum-serverless
circuits.append(circuit) circuits.append(circuit)
# run program # run program
job = serverless.run_program( job = serverless.run(
program=program, program=program,
arguments={ arguments={
"circuits": circuits "circuits": circuits

View File

@ -33,6 +33,7 @@ import os
import tarfile import tarfile
from typing import Dict, Any, Optional, List from typing import Dict, Any, Optional, List
from uuid import uuid4 from uuid import uuid4
import warnings
import ray.runtime_env import ray.runtime_env
import requests import requests
@ -63,6 +64,12 @@ class BaseJobClient:
"""Runs program.""" """Runs program."""
raise NotImplementedError raise NotImplementedError
def run(
self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> "Job":
"""Runs program."""
raise NotImplementedError
def get(self, job_id) -> Optional["Job"]: def get(self, job_id) -> Optional["Job"]:
"""Returns job by job id""" """Returns job by job id"""
raise NotImplementedError raise NotImplementedError
@ -121,6 +128,41 @@ class RayJobClient(BaseJobClient):
] ]
def run_program(self, program: Program, arguments: Optional[Dict[str, Any]] = None): def run_program(self, program: Program, arguments: Optional[Dict[str, Any]] = None):
warnings.warn(
"`run_program` is deprecated. Please, consider using `run` instead.",
DeprecationWarning,
stacklevel=2,
)
arguments = arguments or {}
arguments_string = ""
if program.arguments is not None:
arg_list = []
for key, value in arguments.items():
if isinstance(value, dict):
arg_list.append(f"--{key}='{json.dumps(value)}'")
else:
arg_list.append(f"--{key}={value}")
arguments_string = " ".join(arg_list)
entrypoint = f"python {program.entrypoint} {arguments_string}"
# set program name so OT can use it as parent span name
env_vars = {
**(program.env_vars or {}),
**{OT_PROGRAM_NAME: program.title},
}
job_id = self._job_client.submit_job(
entrypoint=entrypoint,
submission_id=f"qs_{uuid4()}",
runtime_env={
"working_dir": program.working_dir,
"pip": program.dependencies,
"env_vars": env_vars,
},
)
return Job(job_id=job_id, job_client=self)
def run(self, program: Program, arguments: Optional[Dict[str, Any]] = None):
arguments = arguments or {} arguments = arguments or {}
arguments_string = "" arguments_string = ""
if program.arguments is not None: if program.arguments is not None:
@ -168,6 +210,46 @@ class GatewayJobClient(BaseJobClient):
def run_program( # pylint: disable=too-many-locals def run_program( # pylint: disable=too-many-locals
self, program: Program, arguments: Optional[Dict[str, Any]] = None self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> "Job":
warnings.warn(
"`run_program` is deprecated. Please, consider using `run` instead.",
DeprecationWarning,
stacklevel=2,
)
url = f"{self.host}/api/{self.version}/programs/run/"
artifact_file_path = os.path.join(program.working_dir, "artifact.tar")
with tarfile.open(artifact_file_path, "w") as tar:
for filename in os.listdir(program.working_dir):
fpath = os.path.join(program.working_dir, filename)
tar.add(fpath, arcname=filename)
with open(artifact_file_path, "rb") as file:
response_data = safe_json_request(
request=lambda: requests.post(
url=url,
data={
"title": program.title,
"entrypoint": program.entrypoint,
"arguments": json.dumps(
arguments or {}, cls=QiskitObjectsEncoder
),
"dependencies": json.dumps(program.dependencies or []),
},
files={"artifact": file},
headers={"Authorization": f"Bearer {self._token}"},
timeout=REQUESTS_TIMEOUT,
)
)
job_id = response_data.get("id")
if os.path.exists(artifact_file_path):
os.remove(artifact_file_path)
return Job(job_id, job_client=self)
def run( # pylint: disable=too-many-locals
self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> "Job": ) -> "Job":
url = f"{self.host}/api/{self.version}/programs/run/" url = f"{self.host}/api/{self.version}/programs/run/"
artifact_file_path = os.path.join(program.working_dir, "artifact.tar") artifact_file_path = os.path.join(program.working_dir, "artifact.tar")

View File

@ -83,7 +83,7 @@ class Program: # pylint: disable=too-many-instance-attributes
warnings.warn( warnings.warn(
"Passing `arguments` as constructor argument to `Program` is deprecated " "Passing `arguments` as constructor argument to `Program` is deprecated "
"and will be removed in v0.2. " "and will be removed in v0.2. "
"Please, consider passing `arguments` to `run_program` " "Please, consider passing `arguments` to `run` "
"method of `QuantumServerless` object.", "method of `QuantumServerless` object.",
DeprecationWarning, DeprecationWarning,
stacklevel=2, stacklevel=2,

View File

@ -30,6 +30,7 @@ import logging
import os.path import os.path
from dataclasses import dataclass from dataclasses import dataclass
from typing import Optional, List, Dict, Any from typing import Optional, List, Dict, Any
import warnings
import ray import ray
import requests import requests
@ -254,7 +255,7 @@ class Provider(JsonSerializable):
def run_program( def run_program(
self, program: Program, arguments: Optional[Dict[str, Any]] = None self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> Job: ) -> Job:
"""Execute a program as a async job. """(Deprecated) Execute a program as a async job.
Example: Example:
>>> serverless = QuantumServerless() >>> serverless = QuantumServerless()
@ -270,6 +271,43 @@ class Provider(JsonSerializable):
arguments: arguments to run program with arguments: arguments to run program with
program: Program object program: Program object
Returns:
Job
"""
warnings.warn(
"`run_program` is deprecated. Please, consider using `run` instead.",
DeprecationWarning,
stacklevel=2,
)
job_client = self.job_client()
if job_client is None:
logging.warning( # pylint: disable=logging-fstring-interpolation
f"Job has not been submitted as no provider "
f"with remote host has been configured. "
f"Selected provider: {self}"
)
return None
return job_client.run_program(program, arguments)
def run(self, program: Program, arguments: Optional[Dict[str, Any]] = None) -> Job:
"""Execute a program as a async job.
Example:
>>> serverless = QuantumServerless()
>>> program = Program(
>>> "job.py",
>>> arguments={"arg1": "val1"},
>>> dependencies=["requests"]
>>> )
>>> job = serverless.run(program)
>>> # <Job | ...>
Args:
arguments: arguments to run program with
program: Program object
Returns: Returns:
Job Job
""" """
@ -283,7 +321,7 @@ class Provider(JsonSerializable):
) )
return None return None
return job_client.run_program(program, arguments) return job_client.run(program, arguments)
class KuberayProvider(Provider): class KuberayProvider(Provider):
@ -537,8 +575,16 @@ class GatewayProvider(Provider):
def run_program( def run_program(
self, program: Program, arguments: Optional[Dict[str, Any]] = None self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> Job: ) -> Job:
warnings.warn(
"`run_program` is deprecated. Please, consider using `run` instead.",
DeprecationWarning,
stacklevel=2,
)
return self._job_client.run_program(program, arguments) return self._job_client.run_program(program, arguments)
def run(self, program: Program, arguments: Optional[Dict[str, Any]] = None) -> Job:
return self._job_client.run(program, arguments)
def get_jobs(self, **kwargs) -> List[Job]: def get_jobs(self, **kwargs) -> List[Job]:
return self._job_client.list(**kwargs) return self._job_client.list(**kwargs)

View File

@ -88,7 +88,7 @@ class QuantumServerless:
def run_program( def run_program(
self, program: Program, arguments: Optional[Dict[str, Any]] = None self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> Optional[Job]: ) -> Optional[Job]:
"""Execute a program as a async job """(Deprecated) Execute a program as a async job
Example: Example:
>>> serverless = QuantumServerless() >>> serverless = QuantumServerless()
@ -106,10 +106,40 @@ class QuantumServerless:
Returns: Returns:
Job Job
""" """
warnings.warn(
"`run_program` is deprecated. Please, consider using `run` instead.",
DeprecationWarning,
stacklevel=2,
)
if program.arguments is not None: if program.arguments is not None:
arguments = program.arguments arguments = program.arguments
return self._selected_provider.run_program(program, arguments) return self._selected_provider.run_program(program, arguments)
def run(
self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> Optional[Job]:
"""Execute a program as a async job
Example:
>>> serverless = QuantumServerless()
>>> program = Program(
>>> "job.py",
>>> dependencies=["requests"]
>>> )
>>> job = serverless.run(program, {"arg1": 1})
>>> # <Job | ...>
Args:
arguments: arguments to run program with
program: Program object
Returns:
Job
"""
if program.arguments is not None:
arguments = program.arguments
return self._selected_provider.run(program, arguments)
def get_job_by_id(self, job_id: str) -> Optional[Job]: def get_job_by_id(self, job_id: str) -> Optional[Job]:
"""Returns job by job id. """Returns job by job id.

View File

@ -56,7 +56,7 @@ def test_program():
version="0.0.1", version="0.0.1",
) )
job = serverless.run_program(program) job = serverless.run(program)
assert isinstance(job, Job) assert isinstance(job, Job)

View File

@ -56,7 +56,7 @@ def test_state():
wait_for_job_client(serverless) wait_for_job_client(serverless)
job = serverless.run_program( job = serverless.run(
Program("test", entrypoint="job_with_state.py", working_dir=resources_path) Program("test", entrypoint="job_with_state.py", working_dir=resources_path)
) )

View File

@ -98,7 +98,7 @@ program = Program(
working_dir="./" working_dir="./"
) )
job = serverless.run_program(program) job = serverless.run(program)
job.status() job.status()
# <JobStatus.SUCCEEDED: 'SUCCEEDED'> # <JobStatus.SUCCEEDED: 'SUCCEEDED'>

View File

@ -263,7 +263,7 @@
" working_dir=\"./source_files/vqe/\"\n", " working_dir=\"./source_files/vqe/\"\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program, arguments=input_arguments)\n", "job = serverless.run(program, arguments=input_arguments)\n",
"job" "job"
] ]
}, },

View File

@ -213,7 +213,7 @@
" working_dir=\"./source_files/qaoa/\"\n", " working_dir=\"./source_files/qaoa/\"\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program, arguments=input_arguments)\n", "job = serverless.run(program, arguments=input_arguments)\n",
"job" "job"
] ]
}, },

View File

@ -157,7 +157,7 @@
" dependencies=[\"pyscf\"]\n", " dependencies=[\"pyscf\"]\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program)\n", "job = serverless.run(program)\n",
"job" "job"
] ]
}, },

View File

@ -94,7 +94,7 @@
" description=\"Benchmark program to test compute resources.\"\n", " description=\"Benchmark program to test compute resources.\"\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program, arguments={\n", "job = serverless.run(program, arguments={\n",
" \"n_qubits\": 2,\n", " \"n_qubits\": 2,\n",
" \"n_entries\": 2,\n", " \"n_entries\": 2,\n",
" \"depth_of_recursion\": 4,\n", " \"depth_of_recursion\": 4,\n",

View File

@ -84,7 +84,7 @@ Step 3: run program
circuits.append(circuit) circuits.append(circuit)
# run program # run program
job = serverless.run_program( job = serverless.run(
program=program, program=program,
arguments={ arguments={
"circuits": circuits "circuits": circuits

View File

@ -86,7 +86,7 @@
"id": "4dd85621-9ab0-4f34-9ab4-07ad773c5e00", "id": "4dd85621-9ab0-4f34-9ab4-07ad773c5e00",
"metadata": {}, "metadata": {},
"source": [ "source": [
"After importing the necessary classes and configuring them, we can run the program by calling the `run_program()` method of the `QuantumServerless` object:\n", "After importing the necessary classes and configuring them, we can run the program by calling the `run()` method of the `QuantumServerless` object:\n",
"\n", "\n",
"`Program` accepts couple of required parameters:\n", "`Program` accepts couple of required parameters:\n",
"- title - name of the program\n", "- title - name of the program\n",
@ -120,7 +120,7 @@
" working_dir=\"./source_files/\"\n", " working_dir=\"./source_files/\"\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program)\n", "job = serverless.run(program)\n",
"job" "job"
] ]
}, },

View File

@ -170,7 +170,7 @@
" working_dir=\"./source_files/\"\n", " working_dir=\"./source_files/\"\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program, arguments={\"circuits\": circuits})\n", "job = serverless.run(program, arguments={\"circuits\": circuits})\n",
"job" "job"
] ]
}, },

View File

@ -140,7 +140,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"And finally we are creating our program and running it using `run_program` method and passing `arguments` parameter in form of dictionary with `circuit` key and our circuit as value" "And finally we are creating our program and running it using `run` method and passing `arguments` parameter in form of dictionary with `circuit` key and our circuit as value"
] ]
}, },
{ {
@ -168,7 +168,7 @@
" working_dir=\"./source_files/\"\n", " working_dir=\"./source_files/\"\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program, arguments={\"circuit\": circuit})\n", "job = serverless.run(program, arguments={\"circuit\": circuit})\n",
"job" "job"
] ]
}, },

View File

@ -135,7 +135,7 @@
" dependencies=[\"qiskit-experiments\"]\n", " dependencies=[\"qiskit-experiments\"]\n",
")\n", ")\n",
"\n", "\n",
"job = serverless.run_program(program, arguments={\"circuit\": circuit})\n", "job = serverless.run(program, arguments={\"circuit\": circuit})\n",
"job" "job"
] ]
}, },