Skip to content

Commit 2d72a69

Browse files
Hazhzengmaiqbal11
authored andcommitted
Fixed nested namespace library import issue (#492)
1 parent 8fdab32 commit 2d72a69

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

azure/functions_worker/dispatcher.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import threading
1111
import os
1212
import sys
13+
import importlib
1314

1415
import grpc
1516
import pkg_resources
@@ -374,6 +375,9 @@ async def _handle__function_environment_reload_request(self, req):
374375
for var in env_vars:
375376
os.environ[var] = env_vars[var]
376377

378+
# Reload azure namespace for customer's libraries
379+
importlib.reload(sys.modules['azure'])
380+
377381
success_response = protos.FunctionEnvironmentReloadResponse(
378382
result=protos.StatusResult(
379383
status=protos.StatusResult.Success))
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import os
2+
import sys
3+
import shutil
4+
import asyncio
5+
6+
from azure.functions_worker import protos
7+
from azure.functions_worker import testutils
8+
9+
10+
async def vertify_nested_namespace_import():
11+
test_env = {}
12+
request = protos.FunctionEnvironmentReloadRequest(
13+
environment_variables=test_env)
14+
15+
request_msg = protos.StreamingMessage(
16+
request_id='0',
17+
function_environment_reload_request=request)
18+
19+
disp = testutils.create_dummy_dispatcher()
20+
21+
# Mock intepreter starts in placeholder mode
22+
import azure.module_a as mod_a # noqa: F401
23+
24+
# Mock function specialization, load customer's libraries and functionapps
25+
ns_root = os.path.join(
26+
testutils.UNIT_TESTS_ROOT,
27+
'azure_namespace_import',
28+
'namespace_location_b')
29+
test_path = os.path.join(ns_root, 'azure', 'namespace_b', 'module_b')
30+
test_mod_path = os.path.join(test_path, 'test_module.py')
31+
32+
os.makedirs(test_path)
33+
with open(test_mod_path, 'w') as f:
34+
f.write('MESSAGE = "module_b is imported"')
35+
36+
try:
37+
# Mock a customer uses test_module
38+
if sys.argv[1].lower() == 'true':
39+
await disp._handle__function_environment_reload_request(
40+
request_msg)
41+
from azure.namespace_b.module_b import test_module
42+
print(test_module.MESSAGE)
43+
except ModuleNotFoundError:
44+
print('module_b fails to import')
45+
finally:
46+
# Cleanup
47+
shutil.rmtree(ns_root)
48+
49+
50+
if __name__ == '__main__':
51+
loop = asyncio.get_event_loop()
52+
loop.run_until_complete(vertify_nested_namespace_import())
53+
loop.close()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MESSAGE = "module_a is imported"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#! /bin/bash
2+
3+
# $1 controls whether we allow reload module ("true" or "false")
4+
5+
SCRIPT_DIR="$(dirname $0)"
6+
export PYTHONPATH="$SCRIPT_DIR/namespace_location_a:$SCRIPT_DIR/namespace_location_b"
7+
8+
python $SCRIPT_DIR/azure_namespace_import.py $1
9+
10+
unset PYTHONPATH

tests/unittests/test_rpc_messages.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,30 @@ def test_successful_sys_path_import(self):
6969
self._verify_sys_path_import(
7070
'success',
7171
'This module was imported!')
72+
73+
def _verify_azure_namespace_import(self, result, expected_output):
74+
try:
75+
path_import_script = os.path.join(
76+
testutils.UNIT_TESTS_ROOT,
77+
'azure_namespace_import',
78+
'test_azure_namespace_import.sh')
79+
80+
subprocess.run(['chmod +x ' + path_import_script], shell=True)
81+
82+
output = subprocess.check_output(
83+
[path_import_script, result],
84+
stderr=subprocess.STDOUT)
85+
decoded_output = output.decode(sys.stdout.encoding).strip()
86+
self.assertTrue(expected_output in decoded_output)
87+
finally:
88+
self._reset_environ()
89+
90+
def test_failed_azure_namespace_import(self):
91+
self._verify_azure_namespace_import(
92+
'false',
93+
'module_b fails to import')
94+
95+
def test_successful_azure_namespace_import(self):
96+
self._verify_azure_namespace_import(
97+
'true',
98+
'module_b is imported')

0 commit comments

Comments
 (0)