-
Notifications
You must be signed in to change notification settings - Fork 107
Implement base object for handling triggers with basic data types #66
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
Comments
ContextThe original motivation for this feature is to allow creating functions for binding types that are not yet fully supported by the worker. The current behaviour is to simply reject them to be loaded with an error. The proposed solution is to:
Pros:
Cons:
Therefore, implementing this feature doesn't really make it easier for users to work with unsupported bindings. At best this would allow them to quickly prototype a function before the binding/integration is fully supported, but by doing so, they would be writing code that relies on private undocumented data formats. Initial attempt to implement the featureInvariants:
Therefore we want a high-level facade types for the class RawInputData(abc.ABC):
@abc.abstractmethod
def get_str(self) -> typing.Optional[str]:
pass
@abc.abstractmethod
def get_bytes(self) -> typing.Optional[bytes]:
pass
@abc.abstractmethod
def get_int(self) -> typing.Optional[int]:
pass
@abc.abstractmethod
def get_float(self) -> typing.Optional[float]:
pass
@abc.abstractmethod
def get_json(self) -> typing.Any:
pass
# XXX: Not complete! Probably need to add support for TypedData(http)
class RawOutputData(RawInputData):
@abc.abstractmethod
def set_str(self, val: str):
pass
@abc.abstractmethod
def set_bytes(self, val: bytes):
pass
@abc.abstractmethod
def set_int(self, val: int):
pass
@abc.abstractmethod
def set_float(self, val: float):
pass
@abc.abstractmethod
def set_json(self, val: typing.Any):
pass
class GenericBinding(abc.ABC):
@property
@abc.abstractmethod
def raw_data(self) -> RawOutputData:
pass
class GenericTrigger(abc.ABC):
@property
@abc.abstractmethod
def raw_data(self) -> RawInputData:
pass
@property
@abc.abstractmethod
def raw_metadata(self) -> typing.Mapping[str, RawInputData]:
pass The idea is to inherit most of binding and trigger types from either The problem is that this increases the overall complexity of the code. That will result in documentation becoming more complex too. QuestionSo the real question here: do we really want this? Maybe the correct approach is to simply add official support of a binding/trigger/service before documenting it and letting users use it? After all we made it easy to implement new bindings: azure-functions-python-worker/azure/worker/bindings/timer.py Lines 10 to 36 in 9ed3f8a
/cc @asavaritayal @christopheranderson @brettcannon @elprans |
Could you expose the gRPC |
Yes, we could do that. I'm still not sure why that would be useful though:
|
@1st1 neither do I, but you seemed to want to expose something and I was trying to minimize the work to do that. 😉 |
Yeah :) So if @asavaritayal and @christopheranderson are OK with this, I'd prefer to close this issue and simply implement the remaining bindings properly, without exposing any of gRPC low-level messaging to the end-users. |
As per our conf call with @asavaritayal, @pragnagopa, and @paulbatum, we decided to postpone the final decision on this issue. We'll continue implementing high-level rich Python types for bindings for now. We'll reconsider adding a generic type that exposes raw JSON data based on user experience and our own experience implementing rich types. |
Quick update on this issue - Per feedback over the last couple of months, the high-level rich Python types are much easier to use than the basic types we have for node. Since the Closing this issue for now. It can be re-opened if hear otherwise. /cc @paulbatum |
Resurrecting this thread per discussion with @anthonychu. Is it possible that while we support rich types for first class bindings such as HTTP, Blob, Event Grid, etc. , we still allow users to bring their own binding (per our extensibility model) and use it as a basic data type object in their function code? We've got a few new bindings spring up lately - Signal R, Event Hubs, etc. and it seems that Python will start to lose out on scenarios because we're not constantly building support for each of these bindings in the language worker. |
cc: @maiqbal11 @paulbatum We should look into adding support for using context object similar to javascript functions. Exposing context object does not expose TypedData defined in the protobuf which is an internal implementation detail. We should allow following function signatures:
|
Open to comments on this but I think we should keep the function signature consistent for the end user regardless of whether the binding is of a "basic" or "rich" type. For e.g. if def main(req: azure.functions.HttpRequest, msg: str):
name = req.params.get('name')
logging.info(f'property from rich type: {name}')
logging.info(f'basic data type: {msg}') |
One of the reasons why rich bindings are preferred is because we can hide the actual wire format behind a nice abstraction. Exposing raw host data as a |
My point is that I think we shouldn't make it look like a regular binding. Perhaps an explicit |
+1. |
Summarizing our discussion from today's sync - We should use the |
I am struggling with this a little bit because in the case of JavaScript there is no abstraction, and we do not provide any warning. We expect the customer to code against the API surface area that is provided by the binding extension itself. If the binding makes a change to the format of the message, then the user needs to update their code when they update to the new major version of the extension that has that breaking change. Right now we do not have an extensibility model where bindings "plug in" to the language worker, and the Python worker is kind of cheating by referencing the python library that has "built in" knowledge of a certain set of bindings. This is a long winded way of me saying that I'd rather not treat these generic bindings as a special case in Python, because they aren't a special case in our other languages. I look at it as the "base case" and then the additional abstraction that the python worker is doing over some bindings is sugar on top. In the long term, we need to figure out an appropriate architecture for how that abstraction is provided. If we want to update and ship a new version of the python worker every time there's a new binding to add the sugar (perhaps by referencing an updated version of the library), then bindings are no longer acting as a true extensibility model. I'll also mention that I chatted with @pragnagopa and confirmed that if we get to the point where we'd like to allow the python developer to express their datatype through annotations rather than function.json, we'll need to do some additional work in the host to allow that. Today, by the time the host asks the language worker to load a given function, we've already decided on the datatype and its too late for the language worker to change it. @asavaritayal Can you reply to this with a proposed example of how using a generic binding in python should look, based on my comments above? Thanks! |
To define the data type for a standard binding, user should be able to leverage the For example:
{
"bindings": [
{
"name": "myFile",
"type": "apiHubFileTrigger",
"direction": "in",
"path": "samples-workitems",
"connection": "<name of external file connection>",
"dataType": "bytes"
}
]
}
import logging
def main(myFile):
logging.info(f'New file has been added to your Dropbox account: {myFile}') Supported options for If |
@elprans @asavaritayal @paulbatum During our sync yesterday, Elvis had wanted to know whether the |
Update from the sync - don't need to support |
What do I have to do to see the fix?
Redeploy the function?
Otherwise, I’m still seeing the error today.
|
@asavaritayal @pragnagopa We need to bump the host version used for testing as well. Which version should I use? |
@elprans - host is not rolled out yet. You can the build from appveyor to unblock development: https://ci.appveyor.com/project/appsvc/azure-webjobs-sdk-script-y8o14/branch/master/job/9u3n8utn7d08farp/artifacts |
Are you saying the fix is still not available upstream in FunctionApps?
From: Pragna Gopa <[email protected]>
Reply-To: Azure/azure-functions-python-worker <[email protected]>
Date: Tuesday, February 5, 2019 at 12:42 PM
To: Azure/azure-functions-python-worker <[email protected]>
Cc: Joshua Walton <[email protected]>, Manual <[email protected]>
Subject: Re: [Azure/azure-functions-python-worker] Implement base object for handling triggers with basic data types (#66)
EXTERNAL
@elprans<https://github.com/elprans> - host is not rolled out yet. You can the build from appveyor to unblock development: https://ci.appveyor.com/api/buildjobs/k1sofl9yt8n9ocpr/artifacts
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#66 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ArHNPgZqS_GxyAp3SMJB8NnQmn85NiNJks5vKcJ5gaJpZM4SaYS5>.
|
@joshuapwalton - This feature is still in development. This issue will be updated as we make progress. |
@pragnagopa I am not seeing the
The function.json file looks like this: {
"scriptFile": "main.py",
"disabled": false,
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "blob",
"direction": "in",
"name": "file",
"dataType": "binary",
"connection": "AzureWebJobsStorage",
"path": "python-worker-tests/test-bytes.txt"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
} |
@elprans - data_type is a new field added in the protobuff: https://github.com/Azure/azure-functions-language-worker-protobuf/blob/dev/src/proto/FunctionRpc.proto#L318 |
@elprans, I am able to see the |
The generic binding infrastructure now allows annotating the function argument as `str` or `bytes`. This also adds support for `str` and `bytes` binding for the blob functions as an example. The binding data adapter is responsible for checking the declared `dataType` in function.json against the declared parameter type annotation. All existing bindings, except blob, currently refuse to bind if `dataType` is specified. Issue: #66.
It was my mistake, I needed to recompile the protobuf. I pushed the updated PR which incorporates the dataType change. |
The generic binding infrastructure now allows annotating the function argument as `str` or `bytes`. This also adds support for `str` and `bytes` binding for the blob functions as an example. The binding data adapter is responsible for checking the declared `dataType` in function.json against the declared parameter type annotation. All existing bindings, except blob, currently refuse to bind if `dataType` is specified. Issue: #66.
Closing as resolved. |
Re-opening as the work does not satisfy the primary requirement which was to enable support for bindings that don't have rich binding support in the azure.functions library. @elprans please prioritize this. |
* Allow arbitrary bindings with elementary dataType Add a generic binding implementation to allow unknown bindings with `dataType: string` and `dataType: binary`. Fixes: #66 Fixes: #408 * Add support for untyped queue trigger binding * Support unannotated elementary bindings * Decouple rich binding support from the worker Per discussion, the worker no longer includes support for rich bindings by default. The implementation have been moved to azure-functions-python-library, and the runtime dependency on is has been removed.
No description provided.
The text was updated successfully, but these errors were encountered: