Skip to content

Commit 5d21aca

Browse files
authored
Adding more Typing information as generated using monkeytype (#709)
* Type information added and other nit fixes * Removed load_bindings() * Fixing the types * Update the crontab to run at 1 AM
1 parent 04042d5 commit 5d21aca

File tree

13 files changed

+71
-83
lines changed

13 files changed

+71
-83
lines changed

azure-pipelines.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ variables:
99
DOTNET_VERSION: '2.2.207'
1010

1111
schedules:
12-
- cron: "0 0 * * *"
13-
displayName: Daily midnight build
12+
- cron: "0 8 * * 1,2,3,4"
13+
displayName: Monday to Thursday 1 AM build
1414
branches:
1515
include:
1616
- dev

azure_functions_worker/_thirdparty/aio_compat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Backport of asyncio.run() function from Python 3.7.
22
33
Source: https://github.com/python/cpython/blob/
4-
bd093355a6aaf2f4ca3ed153e195da57870a55eb/Lib/asyncio/runners.py
4+
bd093355a6aaf2f4ca3ed153e195da57870a55eb/Lib/asyncio/runners.py
55
"""
66

77

azure_functions_worker/bindings/generic.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import typing
44

55
from . import datumdef
6+
from typing import Any, Optional
67

78

89
class GenericBinding:
@@ -20,8 +21,8 @@ def check_output_type_annotation(cls, pytype: type) -> bool:
2021
return issubclass(pytype, (str, bytes, bytearray))
2122

2223
@classmethod
23-
def encode(cls, obj: typing.Any, *,
24-
expected_type: typing.Optional[type]) -> datumdef.Datum:
24+
def encode(cls, obj: Any, *,
25+
expected_type: Optional[type]) -> datumdef.Datum:
2526
if isinstance(obj, str):
2627
return datumdef.Datum(type='string', value=obj)
2728

azure_functions_worker/bindings/out.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
class Out:
66

7-
def __init__(self):
7+
def __init__(self) -> None:
88
self.__value = None
99

1010
def set(self, val):
1111
self.__value = val
1212

13-
def get(self):
13+
def get(self) -> str:
1414
return self.__value

azure_functions_worker/dispatcher.py

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import inspect
1717

1818
import grpc
19-
import pkg_resources
2019

2120
from . import bindings
2221
from . import functions
@@ -28,6 +27,9 @@
2827
from .logging import enable_console_logging, disable_console_logging
2928
from .utils.tracing import marshall_exception_trace
3029
from .utils.wrappers import disable_feature_by
30+
from asyncio.unix_events import _UnixSelectorEventLoop
31+
from logging import LogRecord
32+
from typing import Optional
3133

3234

3335
class DispatcherMeta(type):
@@ -46,8 +48,10 @@ class Dispatcher(metaclass=DispatcherMeta):
4648

4749
_GRPC_STOP_RESPONSE = object()
4850

49-
def __init__(self, loop, host, port: int, worker_id: str, request_id: str,
50-
grpc_connect_timeout: float, grpc_max_msg_len: int = -1):
51+
def __init__(self, loop: _UnixSelectorEventLoop, host: str, port: int,
52+
worker_id: str, request_id: str,
53+
grpc_connect_timeout: float,
54+
grpc_max_msg_len: int = -1) -> None:
5155
self._loop = loop
5256
self._host = host
5357
self._port = port
@@ -77,20 +81,9 @@ def __init__(self, loop, host, port: int, worker_id: str, request_id: str,
7781
self._grpc_thread = threading.Thread(
7882
name='grpc-thread', target=self.__poll_grpc)
7983

80-
@staticmethod
81-
def load_bindings():
82-
"""Load out-of-tree binding implementations."""
83-
services = {}
84-
85-
for ep in pkg_resources.iter_entry_points('azure.functions.bindings'):
86-
logger.info('Loading binding plugin from %s', ep.module_name)
87-
ep.load()
88-
89-
return services
90-
9184
@classmethod
92-
async def connect(cls, host, port, worker_id, request_id,
93-
connect_timeout):
85+
async def connect(cls, host: str, port: int, worker_id: str,
86+
request_id: str, connect_timeout: float):
9487
loop = asyncio.events.get_event_loop()
9588
disp = cls(loop, host, port, worker_id, request_id, connect_timeout)
9689
disp._grpc_thread.start()
@@ -144,7 +137,7 @@ async def dispatch_forever(self):
144137
self._loop.set_task_factory(self._old_task_factory)
145138
self.stop()
146139

147-
def stop(self):
140+
def stop(self) -> None:
148141
if self._grpc_thread is not None:
149142
self._grpc_resp_queue.put_nowait(self._GRPC_STOP_RESPONSE)
150143
self._grpc_thread.join()
@@ -154,7 +147,7 @@ def stop(self):
154147
self._sync_call_tp.shutdown()
155148
self._sync_call_tp = None
156149

157-
def on_logging(self, record: logging.LogRecord, formatted_msg: str):
150+
def on_logging(self, record: logging.LogRecord, formatted_msg: str) -> None:
158151
if record.levelno >= logging.CRITICAL:
159152
log_level = protos.RpcLog.Critical
160153
elif record.levelno >= logging.ERROR:
@@ -196,11 +189,11 @@ def on_logging(self, record: logging.LogRecord, formatted_msg: str):
196189
rpc_log=protos.RpcLog(**log)))
197190

198191
@property
199-
def request_id(self):
192+
def request_id(self) -> str:
200193
return self._request_id
201194

202195
@property
203-
def worker_id(self):
196+
def worker_id(self) -> str:
204197
return self._worker_id
205198

206199
# noinspection PyBroadException
@@ -524,7 +517,7 @@ def gen(resp_queue):
524517

525518
class AsyncLoggingHandler(logging.Handler):
526519

527-
def emit(self, record):
520+
def emit(self, record: LogRecord) -> None:
528521
# Since we disable console log after gRPC channel is initiated
529522
# We should redirect all the messages into dispatcher
530523
msg = self.format(record)
@@ -533,29 +526,30 @@ def emit(self, record):
533526

534527
class ContextEnabledTask(asyncio.Task):
535528

536-
_AZURE_INVOCATION_ID = '__azure_function_invocation_id__'
529+
AZURE_INVOCATION_ID = '__azure_function_invocation_id__'
537530

538531
def __init__(self, coro, loop):
539532
super().__init__(coro, loop=loop)
540533

541534
current_task = asyncio.Task.current_task(loop)
542535
if current_task is not None:
543536
invocation_id = getattr(
544-
current_task, self._AZURE_INVOCATION_ID, None)
537+
current_task, self.AZURE_INVOCATION_ID, None)
545538
if invocation_id is not None:
546539
self.set_azure_invocation_id(invocation_id)
547540

548-
def set_azure_invocation_id(self, invocation_id):
549-
setattr(self, self._AZURE_INVOCATION_ID, invocation_id)
541+
def set_azure_invocation_id(self, invocation_id: str) -> None:
542+
setattr(self, self.AZURE_INVOCATION_ID, invocation_id)
550543

551544

552-
def get_current_invocation_id():
545+
def get_current_invocation_id() -> Optional[str]:
553546
loop = asyncio._get_running_loop()
554547
if loop is not None:
555548
current_task = asyncio.Task.current_task(loop)
556549
if current_task is not None:
557-
task_invocation_id = getattr(
558-
current_task, ContextEnabledTask._AZURE_INVOCATION_ID, None)
550+
task_invocation_id = getattr(current_task,
551+
ContextEnabledTask.AZURE_INVOCATION_ID,
552+
None)
559553
if task_invocation_id is not None:
560554
return task_invocation_id
561555

azure_functions_worker/functions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class FunctionInfo(typing.NamedTuple):
3232

3333
class FunctionLoadError(RuntimeError):
3434

35-
def __init__(self, function_name, msg):
35+
def __init__(self, function_name: str, msg: str) -> None:
3636
super().__init__(
3737
f'cannot load the {function_name} function: {msg}')
3838

@@ -41,10 +41,10 @@ class Registry:
4141

4242
_functions: typing.MutableMapping[str, FunctionInfo]
4343

44-
def __init__(self):
44+
def __init__(self) -> None:
4545
self._functions = {}
4646

47-
def get_function(self, function_id: str):
47+
def get_function(self, function_id: str) -> FunctionInfo:
4848
try:
4949
return self._functions[function_id]
5050
except KeyError:

azure_functions_worker/loader.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,19 @@
1414

1515
from .constants import MODULE_NOT_FOUND_TS_URL
1616
from .utils.wrappers import attach_message_to_exception
17+
from os import PathLike, fspath
1718

1819

1920
_AZURE_NAMESPACE = '__app__'
2021

2122
_submodule_dirs = []
2223

2324

24-
def register_function_dir(path: os.PathLike):
25-
_submodule_dirs.append(os.fspath(path))
25+
def register_function_dir(path: PathLike) -> None:
26+
_submodule_dirs.append(fspath(path))
2627

2728

28-
def install():
29+
def install() -> None:
2930
if _AZURE_NAMESPACE not in sys.modules:
3031
# Create and register the __app__ namespace package.
3132
ns_spec = importlib.machinery.ModuleSpec(_AZURE_NAMESPACE, None)
@@ -34,7 +35,7 @@ def install():
3435
sys.modules[_AZURE_NAMESPACE] = ns_pkg
3536

3637

37-
def uninstall():
38+
def uninstall() -> None:
3839
pass
3940

4041

azure_functions_worker/logging.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,23 @@ def setup(log_level, log_destination):
5050
error_logger.setLevel(getattr(logging, log_level))
5151

5252

53-
def disable_console_logging():
53+
def disable_console_logging() -> None:
5454
if logger and handler:
5555
logger.removeHandler(handler)
5656

5757
if error_logger and error_handler:
5858
error_logger.removeHandler(error_handler)
5959

6060

61-
def enable_console_logging():
61+
def enable_console_logging() -> None:
6262
if logger and handler:
6363
logger.addHandler(handler)
6464

6565
if error_logger and error_handler:
6666
error_logger.addHandler(error_handler)
6767

6868

69-
def is_system_log_category(ctg: str):
69+
def is_system_log_category(ctg: str) -> bool:
7070
return any(
7171
[ctg.lower().startswith(c) for c in (
7272
'azure_functions_worker',

azure_functions_worker/main.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,4 @@ async def start_async(host, port, worker_id, request_id):
4949
host, port, worker_id, request_id,
5050
connect_timeout=5.0)
5151

52-
disp.load_bindings()
53-
5452
await disp.dispatch_forever()

azure_functions_worker/testutils.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
import json
1616
import logging
1717
import os
18-
import queue
1918
import pathlib
2019
import platform
20+
import queue
21+
import re
2122
import shutil
2223
import socket
2324
import subprocess
@@ -27,17 +28,15 @@
2728
import typing
2829
import unittest
2930
import uuid
30-
import re
3131

3232
import grpc
3333
import requests
3434

3535
from azure_functions_worker._thirdparty import aio_compat
3636
from . import dispatcher
3737
from . import protos
38-
from .utils.common import is_envvar_true
3938
from .constants import PYAZURE_WEBHOST_DEBUG
40-
39+
from .utils.common import is_envvar_true
4140

4241
PROJECT_ROOT = pathlib.Path(__file__).parent.parent
4342
TESTS_ROOT = PROJECT_ROOT / 'tests'
@@ -410,10 +409,10 @@ async def communicate(self, message, *, wait_for):
410409
self._in_queue.put_nowait((message, wait_for))
411410
return await self._out_aqueue.get()
412411

413-
async def _start(self):
412+
async def start(self):
414413
self._server.start()
415414

416-
async def _close(self):
415+
async def close(self):
417416
self._in_queue.put_nowait((_MockWebHostServicer._STOP, None))
418417
self._server.stop(1)
419418

@@ -457,20 +456,18 @@ async def __aenter__(self):
457456
loop = aio_compat.get_running_loop()
458457
self._host = _MockWebHost(loop, self._scripts_dir)
459458

460-
await self._host._start()
461-
462-
self._worker = await dispatcher.Dispatcher.connect(
463-
'127.0.0.1', self._host._port,
464-
self._host.worker_id, self._host.request_id,
465-
connect_timeout=5.0)
459+
await self._host.start()
466460

467-
self._worker.load_bindings()
461+
self._worker = await dispatcher. \
462+
Dispatcher.connect('127.0.0.1', self._host._port,
463+
self._host.worker_id,
464+
self._host.request_id, connect_timeout=5.0)
468465

469466
self._worker_task = loop.create_task(self._worker.dispatch_forever())
470467

471-
done, pending = await asyncio.wait(
472-
[self._host._connected_fut, self._worker_task],
473-
return_when=asyncio.FIRST_COMPLETED)
468+
done, pending = await asyncio. \
469+
wait([self._host._connected_fut, self._worker_task],
470+
return_when=asyncio.FIRST_COMPLETED)
474471

475472
try:
476473
if self._worker_task in done:
@@ -480,7 +477,7 @@ async def __aenter__(self):
480477
raise RuntimeError('could not start a worker thread')
481478
except Exception:
482479
try:
483-
self._host._close()
480+
await self._host.close()
484481
self._worker.stop()
485482
finally:
486483
raise
@@ -498,7 +495,7 @@ async def __aexit__(self, *exc):
498495
self._worker_task = None
499496
self._worker = None
500497

501-
await self._host._close()
498+
await self._host.close()
502499
self._host = None
503500

504501

azure_functions_worker/utils/common.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import os
44

55

6-
def is_true_like(setting: str):
6+
def is_true_like(setting: str) -> bool:
77
if setting is None:
88
return False
99

1010
return setting.lower().strip() in ['1', 'true', 't', 'yes', 'y']
1111

1212

13-
def is_envvar_true(env_key: str):
13+
def is_envvar_true(env_key: str) -> bool:
1414
if os.getenv(env_key) is None:
1515
return False
1616

0 commit comments

Comments
 (0)