Skip to content

Commit c11b37d

Browse files
YunchuWangwangbill1993gavin-aguiar
authored
preserve pystein function app metadata key order (#177)
Co-authored-by: Bill Wang <[email protected]> Co-authored-by: gavin-aguiar <[email protected]>
1 parent b99bf58 commit c11b37d

File tree

4 files changed

+46
-5
lines changed

4 files changed

+46
-5
lines changed

azure/functions/decorators/core.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ def get_dict_repr(self) -> Dict:
115115
116116
:return: Dictionary representation of the binding.
117117
"""
118-
for p in getattr(self, 'init_params', []):
118+
params = list(dict.fromkeys(getattr(self, 'init_params', [])))
119+
for p in params:
119120
if p not in Binding.EXCLUDED_INIT_PARAMS:
120121
self._dict[to_camel_case(p)] = getattr(self, p, None)
121122

azure/functions/decorators/function_app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,11 @@ def _validate_function(self,
214214
# http trigger
215215
if Trigger.is_supported_trigger_type(trigger, HttpTrigger):
216216
if getattr(trigger, 'route', None) is None:
217-
getattr(trigger, 'init_params').add('route')
217+
getattr(trigger, 'init_params').append('route')
218218
setattr(trigger, 'route', function_name)
219219
if getattr(trigger, 'auth_level',
220220
None) is None and auth_level is not None:
221-
getattr(trigger, 'init_params').add('auth_level')
221+
getattr(trigger, 'init_params').append('auth_level')
222222
setattr(trigger, 'auth_level',
223223
parse_singular_param_to_enum(auth_level, AuthLevel))
224224
self._function._is_http_function = True

azure/functions/decorators/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ def wrapper(*args, **kwargs):
5656

5757
self = args[0]
5858

59-
init_params = set(inspect.signature(func).parameters.keys())
60-
init_params.update(kwargs.keys())
59+
init_params = list(inspect.signature(func).parameters.keys())
60+
init_params.extend(list(kwargs.keys()))
6161
for key in kwargs.keys():
6262
if not hasattr(self, key):
6363
setattr(self, key, kwargs[key])

tests/decorators/test_decorators.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,3 +2053,43 @@ def dummy():
20532053
"tableName": "dummy_table_name",
20542054
"connection": "dummy_out_conn"
20552055
})
2056+
2057+
def test_function_app_full_bindings_metadata_key_order(self):
2058+
app = self.func_app
2059+
2060+
@app.route(trigger_arg_name='trigger_name', binding_arg_name='out',
2061+
methods=(HttpMethod.GET, HttpMethod.PATCH),
2062+
auth_level=AuthLevel.FUNCTION, route='dummy_route',
2063+
trigger_extra_fields={"dummy_field": "dummy"},
2064+
binding_extra_fields={"dummy_field": "dummy"})
2065+
@app.table_input(arg_name="in", table_name="dummy_table_name",
2066+
connection="dummy_in_conn",
2067+
row_key="dummy_key",
2068+
partition_key="dummy_partition_key",
2069+
take=1,
2070+
filter="dummy_filter")
2071+
@app.table_output(arg_name="out", table_name="dummy_table_name",
2072+
connection="dummy_out_conn",
2073+
row_key="dummy_key",
2074+
partition_key="dummy_partition_key")
2075+
def dummy():
2076+
pass
2077+
2078+
self._test_function_metadata_order(app)
2079+
2080+
def test_function_app_generic_http_trigger_metadata_key_order(self):
2081+
app = self.func_app
2082+
2083+
@app.generic_trigger(arg_name="req", type=HTTP_TRIGGER)
2084+
def dummy():
2085+
pass
2086+
2087+
self._test_function_metadata_order(app)
2088+
2089+
def _test_function_metadata_order(self, app):
2090+
func = self._get_user_function(app)
2091+
last_metadata_payload = str(func)
2092+
for _ in range(3):
2093+
new_metadata_payload = str(func)
2094+
self.assertEqual(new_metadata_payload, last_metadata_payload)
2095+
last_metadata_payload = new_metadata_payload

0 commit comments

Comments
 (0)