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```
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

View File

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

View File

@ -33,6 +33,7 @@ import os
import tarfile
from typing import Dict, Any, Optional, List
from uuid import uuid4
import warnings
import ray.runtime_env
import requests
@ -63,6 +64,12 @@ class BaseJobClient:
"""Runs program."""
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"]:
"""Returns job by job id"""
raise NotImplementedError
@ -121,6 +128,41 @@ class RayJobClient(BaseJobClient):
]
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_string = ""
if program.arguments is not None:
@ -168,6 +210,46 @@ class GatewayJobClient(BaseJobClient):
def run_program( # pylint: disable=too-many-locals
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":
url = f"{self.host}/api/{self.version}/programs/run/"
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(
"Passing `arguments` as constructor argument to `Program` is deprecated "
"and will be removed in v0.2. "
"Please, consider passing `arguments` to `run_program` "
"Please, consider passing `arguments` to `run` "
"method of `QuantumServerless` object.",
DeprecationWarning,
stacklevel=2,

View File

@ -30,6 +30,7 @@ import logging
import os.path
from dataclasses import dataclass
from typing import Optional, List, Dict, Any
import warnings
import ray
import requests
@ -254,7 +255,7 @@ class Provider(JsonSerializable):
def run_program(
self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> Job:
"""Execute a program as a async job.
"""(Deprecated) Execute a program as a async job.
Example:
>>> serverless = QuantumServerless()
@ -270,6 +271,43 @@ class Provider(JsonSerializable):
arguments: arguments to run program with
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:
Job
"""
@ -283,7 +321,7 @@ class Provider(JsonSerializable):
)
return None
return job_client.run_program(program, arguments)
return job_client.run(program, arguments)
class KuberayProvider(Provider):
@ -537,8 +575,16 @@ class GatewayProvider(Provider):
def run_program(
self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> Job:
warnings.warn(
"`run_program` is deprecated. Please, consider using `run` instead.",
DeprecationWarning,
stacklevel=2,
)
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]:
return self._job_client.list(**kwargs)

View File

@ -88,7 +88,7 @@ class QuantumServerless:
def run_program(
self, program: Program, arguments: Optional[Dict[str, Any]] = None
) -> Optional[Job]:
"""Execute a program as a async job
"""(Deprecated) Execute a program as a async job
Example:
>>> serverless = QuantumServerless()
@ -106,10 +106,40 @@ class QuantumServerless:
Returns:
Job
"""
warnings.warn(
"`run_program` is deprecated. Please, consider using `run` instead.",
DeprecationWarning,
stacklevel=2,
)
if program.arguments is not None:
arguments = 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]:
"""Returns job by job id.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -86,7 +86,7 @@
"id": "4dd85621-9ab0-4f34-9ab4-07ad773c5e00",
"metadata": {},
"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",
"`Program` accepts couple of required parameters:\n",
"- title - name of the program\n",
@ -120,7 +120,7 @@
" working_dir=\"./source_files/\"\n",
")\n",
"\n",
"job = serverless.run_program(program)\n",
"job = serverless.run(program)\n",
"job"
]
},

View File

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

View File

@ -140,7 +140,7 @@
"cell_type": "markdown",
"metadata": {},
"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",
")\n",
"\n",
"job = serverless.run_program(program, arguments={\"circuit\": circuit})\n",
"job = serverless.run(program, arguments={\"circuit\": circuit})\n",
"job"
]
},

View File

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