Skip to content

Commit 710c606

Browse files
korgan00Tansito
andauthored
Return function type (#1626)
* return function type * black & lint * black & lint * fix serializers and add feature to client * added integration test * fixed types * fixed types * change to static variables * lint * test a new configuration for the k8s test * use 0.20.0 kind * install simpler dependencies * use kind 0.27.0 * last updates to the gha configuration * test with 2gb of memory * setup memory to 3 for the tests --------- Co-authored-by: David <[email protected]>
1 parent 34e8203 commit 710c606

File tree

7 files changed

+59
-45
lines changed

7 files changed

+59
-45
lines changed

.github/workflows/kubernetes-deploy.yaml

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ jobs:
1212
runs-on: ubuntu-latest
1313
timeout-minutes: 45
1414
steps:
15-
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #4.1.7
15+
- uses: actions/checkout@v4.2.2
1616
- name: Install Kind
1717
run: |
18-
curl -Lo ./kind "https://github.com/kubernetes-sigs/kind/releases/download/v0.20.0/kind-$(uname)-amd64"
18+
curl -Lo ./kind "https://github.com/kubernetes-sigs/kind/releases/download/v0.27.0/kind-$(uname)-amd64"
1919
chmod +x ./kind
2020
sudo mv kind /usr/local/bin
2121
which kind
2222
- name: Create Kind cluster
2323
uses: chainguard-dev/actions/setup-kind@main
2424
with:
25-
k8s-version: 1.29.x
25+
k8s-version: 1.31.x
2626
kind-worker-count: 0
2727
- name: Label nodes
2828
run: kubectl label node kind-control-plane has-gpu=gpu has-cpu=cpu
@@ -44,14 +44,13 @@ jobs:
4444
helm dependency build
4545
helm install qs \
4646
--set platform=kind \
47-
--set repositoryEnable=false \
4847
--set nginxIngressControllerEnable=false \
4948
--set gateway.image.repository=gateway \
5049
--set gateway.image.tag=test \
5150
--set gateway.application.ray.nodeImage=ray:test \
5251
--set gateway.application.ray.cpu=1 \
52+
--set gateway.application.ray.memory=3 \
5353
--set gateway.application.debug=1 \
54-
--set gateway.application.limits.keepClusterOnComplete=false \
5554
--set gateway.application.authMockproviderRegistry=test \
5655
.
5756
GATEWAY=$(kubectl get pod -l app.kubernetes.io/name=gateway -o name)
@@ -62,19 +61,9 @@ jobs:
6261
python-version: "3.11"
6362
- name: Install dependencies
6463
run: |
65-
python -m pip install --upgrade pip==24.2
64+
python -m pip install --upgrade pip>=24.2
6665
cd client
6766
pip install . --no-cache-dir
68-
pip install --no-cache-dir \
69-
ipywidgets==8.1.1 \
70-
circuit-knitting-toolbox>=0.6.0 \
71-
matplotlib==3.7.1 \
72-
pyscf==2.2.1 \
73-
scipy==1.10 \
74-
qiskit-ibm-provider>=0.9.0 \
75-
qiskit-aer>=0.13.3 \
76-
certifi==2024.7.4
77-
pip install nbmake==1.5.4 pytest==8.3.2
7867
- name: Run tests
7968
run: |
8069
kubectl patch svc gateway -p '{"spec": {"type": "LoadBalancer"}}'

client/qiskit_serverless/core/clients/serverless_client.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -432,15 +432,12 @@ def functions(self, **kwargs) -> List[RunnableQiskitFunction]:
432432
)
433433
)
434434

435+
for program_data in response_data:
436+
program_data["client"] = self
437+
435438
return [
436-
RunnableQiskitFunction(
437-
client=self,
438-
title=program.get("title"),
439-
provider=program.get("provider", None),
440-
raw_data=program,
441-
description=program.get("description"),
442-
)
443-
for program in response_data
439+
RunnableQiskitFunction.from_json(program_data)
440+
for program_data in response_data
444441
]
445442

446443
@_trace_functions("get_by_title")
@@ -461,12 +458,9 @@ def function(
461458
)
462459
)
463460

464-
return RunnableQiskitFunction(
465-
client=self,
466-
title=response_data.get("title"),
467-
provider=response_data.get("provider", None),
468-
raw_data=response_data,
469-
)
461+
response_data["client"] = self
462+
the_function = RunnableQiskitFunction.from_json(response_data)
463+
return the_function
470464

471465
#####################
472466
####### FILES #######

client/qiskit_serverless/core/function.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@
3030
import dataclasses
3131
import warnings
3232
from dataclasses import dataclass
33-
from typing import Optional, Dict, List, Any, Tuple, Union
33+
from typing import ClassVar, Literal, Optional, Dict, List, Any, Tuple, Union
3434

3535
from qiskit_serverless.core.job import (
3636
Job,
3737
Configuration,
3838
)
3939

40+
GenericType = Literal["GENERIC"]
41+
ApplicationType = Literal["APPLICATION"]
42+
CircuitType = Literal["CIRCUIT"]
43+
4044

4145
@dataclass
4246
class QiskitFunction: # pylint: disable=too-many-instance-attributes
@@ -54,6 +58,10 @@ class QiskitFunction: # pylint: disable=too-many-instance-attributes
5458
version: version of a program
5559
"""
5660

61+
GENERIC: ClassVar[GenericType] = "GENERIC"
62+
APPLICATION: ClassVar[ApplicationType] = "APPLICATION"
63+
CIRCUIT: ClassVar[CircuitType] = "CIRCUIT"
64+
5765
title: str
5866
provider: Optional[str] = None
5967
entrypoint: Optional[str] = None
@@ -67,6 +75,7 @@ class QiskitFunction: # pylint: disable=too-many-instance-attributes
6775
image: Optional[str] = None
6876
validate: bool = True
6977
schema: Optional[str] = None
78+
type: Union[GenericType, ApplicationType, CircuitType] = GENERIC
7079

7180
def __post_init__(self):
7281
title_has_provider = "/" in self.title
@@ -154,7 +163,7 @@ def __init__( # pylint: disable=too-many-positional-arguments
154163
@classmethod
155164
def from_json(cls, data: Dict[str, Any]):
156165
"""Reconstructs QiskitPattern from dictionary."""
157-
field_names = set(f.name for f in dataclasses.fields(QiskitFunction))
166+
field_names = set(f.name for f in dataclasses.fields(RunnableQiskitFunction))
158167
client = data["client"]
159168
return RunnableQiskitFunction(
160169
client, **{k: v for k, v in data.items() if k in field_names}

client/qiskit_serverless/core/job.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import os
3535
import time
3636
import warnings
37-
from typing import Dict, Any, Optional, Union
37+
from typing import ClassVar, Dict, Any, Literal, Optional, Union
3838
from dataclasses import dataclass
3939

4040
import ray.runtime_env
@@ -111,21 +111,35 @@ def filtered_logs(self, job_id: str, **kwargs) -> str:
111111
"""
112112

113113

114+
PendingType = Literal["PENDING"]
115+
RunningType = Literal["RUNNING"]
116+
StoppedType = Literal["STOPPED"]
117+
SucceededType = Literal["SUCCEEDED"]
118+
FailedType = Literal["FAILED"]
119+
QueuedType = Literal["QUEUED"]
120+
# RUNNING statuses
121+
MappingType = Literal["MAPPING"]
122+
OptimizingHardwareType = Literal["OPTIMIZING_HARDWARE"]
123+
WaitingQpuType = Literal["WAITING_QPU"]
124+
ExecutingQpuType = Literal["EXECUTING_QPU"]
125+
PostProcessingType = Literal["POST_PROCESSING"]
126+
127+
114128
class Job:
115129
"""Job."""
116130

117-
PENDING = "PENDING"
118-
RUNNING = "RUNNING"
119-
STOPPED = "STOPPED"
120-
SUCCEEDED = "SUCCEEDED"
121-
FAILED = "FAILED"
122-
QUEUED = "QUEUED"
131+
PENDING: ClassVar[PendingType] = "PENDING"
132+
RUNNING: ClassVar[RunningType] = "RUNNING"
133+
STOPPED: ClassVar[StoppedType] = "STOPPED"
134+
SUCCEEDED: ClassVar[SucceededType] = "SUCCEEDED"
135+
FAILED: ClassVar[FailedType] = "FAILED"
136+
QUEUED: ClassVar[QueuedType] = "QUEUED"
123137
# RUNNING statuses
124-
MAPPING = "MAPPING"
125-
OPTIMIZING_HARDWARE = "OPTIMIZING_HARDWARE"
126-
WAITING_QPU = "WAITING_QPU"
127-
EXECUTING_QPU = "EXECUTING_QPU"
128-
POST_PROCESSING = "POST_PROCESSING"
138+
MAPPING: ClassVar[MappingType] = "MAPPING"
139+
OPTIMIZING_HARDWARE: ClassVar[OptimizingHardwareType] = "OPTIMIZING_HARDWARE"
140+
WAITING_QPU: ClassVar[WaitingQpuType] = "WAITING_QPU"
141+
EXECUTING_QPU: ClassVar[ExecutingQpuType] = "EXECUTING_QPU"
142+
POST_PROCESSING: ClassVar[PostProcessingType] = "POST_PROCESSING"
129143

130144
def __init__(
131145
self,

gateway/api/v1/serializers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Meta(serializers.ProgramSerializer.Meta):
3131
"provider",
3232
"description",
3333
"documentation_url",
34+
"type",
3435
]
3536

3637

@@ -91,6 +92,7 @@ def validate(self, attrs): # pylint: disable=too-many-branches
9192
raise ValidationError(
9293
f"Custom images must be in {provider_instance.registry}."
9394
)
95+
9496
return super().validate(attrs)
9597

9698
class Meta(serializers.UploadProgramSerializer.Meta):
@@ -103,12 +105,13 @@ class Meta(serializers.UploadProgramSerializer.Meta):
103105
"image",
104106
"provider",
105107
"description",
108+
"type",
106109
]
107110

108111

109112
class RunProgramSerializer(serializers.RunProgramSerializer):
110113
"""
111-
RunExistingProgramSerializer is used by the /upload end-point
114+
RunExistingProgramSerializer is used by the /run end-point
112115
"""
113116

114117

gateway/tests/api/test_v1_serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,14 @@ def test_upload_program_serializer_creates_program(self):
6161

6262
title = "Hello world"
6363
entrypoint = "pattern.py"
64+
type = Program.CIRCUIT
6465
arguments = "{}"
6566
dependencies = "[]"
6667

6768
data = {}
6869
data["title"] = title
6970
data["entrypoint"] = entrypoint
71+
data["type"] = type
7072
data["arguments"] = arguments
7173
data["dependencies"] = dependencies
7274
data["artifact"] = upload_file
@@ -76,6 +78,7 @@ def test_upload_program_serializer_creates_program(self):
7678

7779
program: Program = serializer.save(author=user)
7880
self.assertEqual(title, program.title)
81+
self.assertEqual(type, program.type)
7982
self.assertEqual(entrypoint, program.entrypoint)
8083
self.assertEqual(dependencies, program.dependencies)
8184

tests/docker/test_docker.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ def test_simple_function(self, base_client: BaseClient):
3636
runnable_function = base_client.upload(simple_function)
3737

3838
assert runnable_function is not None
39+
assert runnable_function.type == "GENERIC"
3940

4041
runnable_function = base_client.function(simple_function.title)
4142

4243
assert runnable_function is not None
44+
assert runnable_function.type == "GENERIC"
4345

4446
job = runnable_function.run()
4547

0 commit comments

Comments
 (0)