Skip to content

Commit 3b78bda

Browse files
committed
Merge branch 'dev'
2 parents 271642c + 3c79385 commit 3b78bda

File tree

63 files changed

+344
-452
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+344
-452
lines changed

.ci/appveyor_setup_worker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88

99
def main():
10-
worker_dir = pathlib.Path(tempfile.mkdtemp()) / 'python'
10+
worker_dir = pathlib.Path(tempfile.mkdtemp())
1111
os.makedirs(worker_dir)
12-
worker_src = pathlib.Path(__file__).parent.parent / 'python' / 'worker.py'
12+
worker_src = pathlib.Path(__file__).parent.parent / 'worker.py'
1313

1414
shutil.copyfile(worker_src, worker_dir / 'worker.py')
1515
with open(worker_dir / 'worker.config.json', 'w') as f:

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,3 @@ ENV/
103103

104104
.testconfig
105105
.pytest_cache
106-
tests/*_functions/bin/

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
dist: trusty
22

33
env:
4-
- DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_VERSION=2.1.300
4+
- DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_VERSION=2.1.402
55

66
branches:
77
only:

ISSUE_TEMPLATE.md

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11

22
<!--
3-
Please provide a succinct description of the issue. Please make an effort to fill in the all the sections below or we may close your issue for being low quality.
3+
Please describe your issue or feature request below.
44
-->
55

66
#### Investigative information
77

88
Please provide the following:
99

1010
- Timestamp:
11-
- Function App version (1.0 or 2.0-beta):
1211
- Function App name:
1312
- Function name(s) (as appropriate):
14-
- Invocation ID:
15-
- Region:
16-
17-
<!--
18-
If you don't want to share your Function App name or Functions names on GitHub, please be sure to provide your Invocation ID, Timestamp, and Region - we can use this to look up your Function App/Function. Provide an invocation id per Function. See the [wiki](https://github.com/Azure/azure-webjobs-sdk-script/wiki/Sharing-Your-Function-App-name-privately) for more details.
19-
-->
2013

2114
#### Repro steps
2215

@@ -27,6 +20,7 @@ Example:
2720
2821
1. Step A
2922
2. Step B
23+
3024
-->
3125

3226
#### Expected behavior
@@ -63,33 +57,31 @@ Example:
6357

6458
Provide any related information
6559

66-
* Programming language used
6760
* Links to source
6861
* Bindings used
62+
* Dependencies
63+
6964
<!-- Uncomment this if you want to include your source (wrap it in details to make browsing easier)
7065
<details>
7166
<summary>Source</summary>
7267
73-
```csharp
74-
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.AuthLevelValue, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
75-
{
76-
log.Info("C# HTTP trigger function processed a request.");
77-
78-
// parse query parameter
79-
string name = req.GetQueryNameValuePairs()
80-
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
81-
.Value;
68+
```python
69+
# __init__.py
8270
83-
// Get request body
84-
dynamic data = await req.Content.ReadAsAsync<object>();
71+
def main(req: func.HttpRequest) -> func.HttpResponse:
72+
logging.info('Python HTTP trigger function processed a request.')
8573
86-
// Set name to query string or body data
87-
name = name ?? data?.name;
74+
return "Done"
75+
```
8876
89-
return name == null
90-
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
91-
: req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
92-
}
77+
```txt
78+
azure-functions==1.0.0a4
79+
azure-functions-worker==1.0.0a4
80+
grpcio==1.14.2
81+
grpcio-tools==1.14.2
82+
protobuf==3.6.1
83+
six==1.11.0
9384
```
85+
9486
</details>
9587
-->

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,27 @@ This repository will host the Python language worker implementation for Azure Fu
77
88
# Overview
99

10-
Python support for Functions is based on [Python3.6](https://www.python.org/downloads/release/python-360/), [Functions on Linux](https://blogs.msdn.microsoft.com/appserviceteam/2017/11/15/functions-on-linux-preview/) and the [V2 Runtime](https://docs.microsoft.com/en-us/azure/azure-functions/functions-versions).
10+
Python support for Azure Functions is based on Python3.6, serverless hosting on Linux and the Functions 2.0 runtime.
1111

1212
Here is the current status of Python in Azure Functions:
1313

1414
What's available?
1515

16-
- Develop using Functions Core Tools (CLI)
17-
- Publish your Python functions using an App Service Plan on Linux
18-
- Triggers / Bindings : HTTP/Webhook, Blob, Queue, Timer, Cosmos DB, Event Grid, Event Hubs and Service Bus
19-
- Publish a custom image to Azure
16+
- Develop using the Azure Functions Core Tools (CLI)
17+
- Triggers / Bindings : HTTP, Blob, Queue, Timer, Cosmos DB, Event Grid, Event Hubs and Service Bus
18+
- Publish your functions to a [serverless linux app in Azure](https://aka.ms/functions-consumptionlinux-preview)
19+
- Build, test, debug and publish using Visual Studio Code
2020

2121
What's coming?
2222

23-
- Publish your Python functions using the consumption (serverless) plan
24-
- Build, test, debug and publish using Visual Studio Code
2523
- Triggers / Bindings : IoT Hub
2624

2725
# Get Started
2826

29-
- [Build and publish using the Functions Core Tools](https://github.com/Azure/azure-functions-python-worker/wiki/Create-Function-(CLI))
30-
- [Python developer guide](https://pythondeveloperguide.azurewebsites.net/)
27+
- [Create your first Python function](https://github.com/Azure/azure-functions-python-worker/wiki/Create-your-first-Python-function)
28+
- [Developer guide](https://github.com/Azure/azure-functions-python-worker/wiki/Developer-Guide)
3129
- [Binding API reference](https://pythondeveloperguide.azurewebsites.net/api.html#azure-functions-reference)
30+
- [Develop using VS Code](https://github.com/Azure/azure-functions-python-worker/wiki/Develop-using-VS-Code)
3231

3332
# Give Feedback
3433

appveyor.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,17 @@ environment:
1212
PIP_NO_WARN_SCRIPT_LOCATION: 0
1313
PIP_DISABLE_PIP_VERSION_CHECK: 1
1414
DOTNET_CLI_TELEMETRY_OPTOUT: 1
15-
DOTNET_VERSION: 2.1.300
15+
DOTNET_VERSION: 2.1.402
1616

1717
matrix:
1818
- PYTHON_VERSION: 3.6
1919
- PYTHON_VERSION: 3.7
2020

21+
# We must run tests sequentially as most integration tests
22+
# depend on the functino app state, which would get mangled
23+
# with multiple test jobs being run in parallel.
24+
max_jobs: 1
25+
2126
for:
2227
-
2328
matrix:

azure/functions_worker/bindings/http.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ class HttpRequest(azf_abc.HttpRequest):
1515
__body_bytes: typing.Optional[bytes]
1616
__body_str: typing.Optional[str]
1717

18-
def __init__(self, method: str, url: str,
18+
def __init__(self, method: str, url: str, *,
1919
headers: typing.Mapping[str, str],
2020
params: typing.Mapping[str, str],
21+
route_params: typing.Mapping[str, str],
2122
body_type: meta.TypedDataKind,
2223
body: typing.Union[str, bytes]) -> None:
2324
self.__method = method
2425
self.__url = url
2526
self.__headers = azf_http.HttpRequestHeaders(headers)
2627
self.__params = types.MappingProxyType(params)
28+
self.__route_params = types.MappingProxyType(route_params)
2729
self.__body_type = body_type
2830

2931
if isinstance(body, str):
@@ -52,6 +54,10 @@ def headers(self):
5254
def params(self):
5355
return self.__params
5456

57+
@property
58+
def route_params(self):
59+
return self.__route_params
60+
5561
def get_body(self) -> bytes:
5662
if self.__body_bytes is None:
5763
assert self.__body_str is not None
@@ -147,5 +153,6 @@ def from_proto(cls, data: protos.TypedData, *,
147153
url=data.http.url,
148154
headers=data.http.headers,
149155
params=data.http.query,
156+
route_params=data.http.params,
150157
body_type=body_type,
151158
body=body)

azure/functions_worker/bindings/meta.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import abc
2+
import collections.abc
23
import datetime
34
import enum
45
import json
56
import typing
67

78
from .. import protos
9+
from .. import typing_inspect
810

911

1012
class TypedDataKind(enum.Enum):
@@ -211,6 +213,28 @@ def to_proto(cls, obj: typing.Any, *,
211213
pass
212214

213215

216+
def is_iterable_type_annotation(annotation: object, pytype: object) -> bool:
217+
is_iterable_anno = (
218+
typing_inspect.is_generic_type(annotation) and
219+
issubclass(typing_inspect.get_origin(annotation),
220+
collections.abc.Iterable)
221+
)
222+
223+
if not is_iterable_anno:
224+
return False
225+
226+
args = typing_inspect.get_args(annotation)
227+
if not args:
228+
return False
229+
230+
if isinstance(pytype, tuple):
231+
return any(isinstance(t, type) and issubclass(t, arg)
232+
for t in pytype for arg in args)
233+
else:
234+
return any(isinstance(pytype, type) and issubclass(pytype, arg)
235+
for arg in args)
236+
237+
214238
def is_binding(bind_name: str) -> bool:
215239
return bind_name in _ConverterMeta._binding_types
216240

azure/functions_worker/bindings/queue.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import collections.abc
12
import datetime
23
import json
34
import typing
@@ -99,7 +100,11 @@ class QueueMessageOutConverter(meta.OutConverter, binding='queue'):
99100

100101
@classmethod
101102
def check_output_type_annotation(cls, pytype: type) -> bool:
102-
return issubclass(pytype, (azf_abc.QueueMessage, str, bytes))
103+
valid_types = (azf_abc.QueueMessage, str, bytes)
104+
return (
105+
meta.is_iterable_type_annotation(pytype, valid_types) or
106+
(isinstance(pytype, type) and issubclass(pytype, valid_types))
107+
)
103108

104109
@classmethod
105110
def to_proto(cls, obj: typing.Any, *,
@@ -118,6 +123,25 @@ def to_proto(cls, obj: typing.Any, *,
118123
})
119124
)
120125

126+
elif isinstance(obj, collections.abc.Iterable):
127+
msgs = []
128+
for item in obj:
129+
if isinstance(item, str):
130+
msgs.append(item)
131+
elif isinstance(item, azf_queue.QueueMessage):
132+
msgs.append({
133+
'id': item.id,
134+
'body': item.get_body().decode('utf-8')
135+
})
136+
else:
137+
raise NotImplementedError(
138+
'invalid data type in output '
139+
'queue message list: {}'.format(type(item)))
140+
141+
return protos.TypedData(
142+
json=json.dumps(msgs)
143+
)
144+
121145
raise NotImplementedError
122146

123147
@classmethod

azure/functions_worker/dispatcher.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ async def _handle__function_load_request(self, req):
199199
func = loader.load_function(
200200
func_request.metadata.name,
201201
func_request.metadata.directory,
202-
func_request.metadata.script_file)
202+
func_request.metadata.script_file,
203+
func_request.metadata.entry_point)
203204

204205
self._functions.add_function(
205206
function_id, func, func_request.metadata)

0 commit comments

Comments
 (0)