-
Notifications
You must be signed in to change notification settings - Fork 1
Initial implementation #1
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
Conversation
a0db8c4
to
2733044
Compare
4c284df
to
9bdf24d
Compare
fbb91b0
to
659557b
Compare
96f9be3
to
9711999
Compare
fa76eac
to
706b354
Compare
... | ||
|
||
|
||
class LazyValueT(Protocol): |
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.
But I thought we were removing sync form? At which point is there value here?
"""Request or response data.""" | ||
|
||
|
||
class Serializer(Protocol): |
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.
It's not incorrect, it's just too limiting and not common for these use cases. I think we should revisit this since it makes sense for serializer to be a base class one extends instead of duck-typed.
... | ||
|
||
|
||
class LazyValueT(Protocol): |
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.
Yeah, I think my main problem was that this didn't make sense as a protocol
) | ||
return defn | ||
|
||
def _validation_errors(self) -> list[str]: |
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.
Can we get a general decision on operation-less Nexus service contracts and whether we generally believe they are valid? A dataclass with no fields may be valid, but a service with no calls may not be.
from nexusrpc.handler._operation_handler import OperationHandler | ||
|
||
|
||
def get_service_definition( |
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.
Concern about the name is different than concern about the placement. I think there's not a need to clutter the top-level API with a top-level function here. Whether we call this from_class
or get_from_class
or whatever I think is a secondary question (I don't see a from_whatever
to be a constructor, but can be documented away).
src/nexusrpc/handler/_common.py
Outdated
|
||
|
||
@dataclass(frozen=True) | ||
class OperationContext: |
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.
I think it's also a signal of intent as well (i.e. "this is always used as a base class")
... | ||
|
||
|
||
class BaseServiceCollectionHandler(AbstractHandler): |
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.
👍 Would definitely like to reduce class/abstraction count if we can
) | ||
self.service_handlers[sh.service.name] = sh | ||
|
||
async def start_operation( |
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.
👍 I trust the removal of the unused syncio stuff is being tracked
def service_handler(cls: Type[ServiceHandlerT]) -> Type[ServiceHandlerT]: ... | ||
|
||
|
||
# TODO(preview): allow service to be provided as positional argument? |
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.
I guess what I mean is why is service
before *
in the impl but after the *
here?
self.headers = headers | ||
self.stream = stream | ||
|
||
def consume(self, as_type: Optional[Type[Any]] = None) -> Any: |
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.
A thought while we're here - arguably a sync implementation should allow async operations and provide an event loop to run them on via run_coroutine_threadsafe
similar to how an executor is provided to go from async to sync.
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.
Approving with the understanding that things mentioned here will be revisited soon
f1c5988
to
0673817
Compare
Nexus Python SDK initial content.
For an overview of the user experience of implementing and calling Nexus handlers, see the Temporal sample, and tests in this PR.