-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Function and jobs refactor - resolve circular dependencies #1517
Conversation
# Conflicts: # client/qiskit_serverless/core/client.py # client/qiskit_serverless/core/clients/local_client.py # client/qiskit_serverless/core/clients/ray_client.py # client/qiskit_serverless/core/clients/serverless_client.py
# Conflicts: # client/qiskit_serverless/core/client.py # client/qiskit_serverless/core/clients/local_client.py # client/qiskit_serverless/core/clients/ray_client.py # client/qiskit_serverless/core/clients/serverless_client.py # client/qiskit_serverless/core/files.py # client/qiskit_serverless/core/function.py # client/qiskit_serverless/core/job.py
@abstractmethod | ||
def run( | ||
self, | ||
program: Union[QiskitFunction, str], | ||
arguments: Optional[Dict[str, Any]] = None, | ||
config: Optional[Configuration] = None, | ||
) -> Job: | ||
"""Execute a program as a async job. | ||
|
||
Example: | ||
>>> serverless = QiskitServerless() | ||
>>> program = QiskitFunction( | ||
>>> "job.py", | ||
>>> arguments={"arg1": "val1"}, | ||
>>> dependencies=["requests"] | ||
>>> ) | ||
>>> job = serverless.run(program) | ||
>>> # <Job | ...> | ||
|
||
Args: | ||
arguments: arguments to run program with | ||
program: Program object | ||
|
||
Returns: | ||
Job | ||
""" | ||
|
||
@abstractmethod | ||
def status(self, job_id: str) -> str: | ||
"""Check status.""" | ||
|
||
@abstractmethod | ||
def stop( | ||
self, job_id: str, service: Optional[QiskitRuntimeService] = None | ||
) -> Union[str, bool]: | ||
"""Stops job/program.""" | ||
|
||
@abstractmethod | ||
def result(self, job_id: str) -> Any: | ||
"""Return results.""" | ||
|
||
@abstractmethod | ||
def logs(self, job_id: str) -> str: | ||
"""Return logs.""" | ||
|
||
@abstractmethod | ||
def filtered_logs(self, job_id: str, **kwargs) -> str: | ||
"""Return filtered logs.""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This methods are defined in new RunService and JobClient abstract classes.
client/qiskit_serverless/core/job.py
Outdated
@@ -76,13 +77,44 @@ class Configuration: # pylint: disable=too-many-instance-attributes | |||
auto_scaling: Optional[bool] = False | |||
|
|||
|
|||
class JobClient(ABC): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we commented through a call JobClient
I would like to rename it to JobService
to match it with the current RunService
.
Apart from that I saw everything good, really good job here @korgan00
@IceKhan13 if you can take a look to this PR too and give some feedback to @korgan00 it would be nice! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good job @korgan00 😄
I have a question regarding function.py
and job.py
.
job.py
contains three classes:Configuration
,JobService
andJob
function.py
contains another three classes:QiskitFunction
,RunService
andRunnableQiskitFunction
.
Would it make sense to have some of these classes in a separated file? I was thinking that maybe RunService
and JobService
could be in another file
version: version of a program | ||
""" | ||
|
||
_run_service: RunService = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_run_service: RunService = None | |
_run_service: Optional[RunService] = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case i think it shouldnt be optional because, to be runnable it needs an associated run service. If run_service
is None
, then it is just a QiskitFunction
Since they are very coupled to that files, I added it to the same file, but im ok with splitting it. What do you think @IceKhan13 , @Tansito ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
woohoo, circular deps gone!
LGTM
THank you!
I think by now having them in the same file is good enough, as we commented we are not expecting to re use them in other places in the near future, @korgan00 👍 |
Summary
Depends on #1513
Details and comments
To resolve the circular dependencies,
QiskitFunction
andJob
defines an interface (pure abstract class in python) with their needs:RunService
andJobService
. The oldclient: Any
variable will be replaced with_run_service: RunService
and_job_service: JobService
. TheBaseClient
should implement this interfaces.We are achieving multiple objectives:
QiskitFunction
andJob
doesn't need to importBaseClient
, the imports are in theBaseClient
side._run_service
and_job_service
variables now can be resolved by the IDE and offer autocompletion and type-checking of the linter and code-quality tools.QiskitFunction
andJob
are decoupled.Additionally:
QiskitFunction
had therun
method that raised an exception by default if you create it and it worked when it is retrieved from the client.The
QiskitFunction
no longer has arun
method because it doesn't work without a client.RunnableQiskitFunction
inherits from it, implements therun
and receives the client as a not optionalrun_service
. This is less error prone.Client's
upload
,function
andfunctions
now returnRunnableQiskitFunction
by default.