Skip to content

Commit cf288d4

Browse files
batzuuUtkarsh Tyagirahur-NI
authored
Fixing size parameter handling in len-mechanism to handle function parameters with different size parameters (#2138)
* changes to handle functions with multiple length size params * added MultipleArraysDifferentSize function in nifake to validate len handling * changes var names * adding noqa to suppress flake error for global _instance_lock * Removing global _instance_lock from _library_singleton.py.mako file * Updating based on code review comments * Remove mechanism from len/ivi size parameters * Updated tests per review comments - using 'passed-in' as the default mechanism * Updating the default mechanism in test_metadata_find.py as well. --------- Co-authored-by: Utkarsh Tyagi <utkarsh.tyagi@emerson.com> Co-authored-by: Rahul R <rahul.r@emerson.com>
1 parent e4d39c7 commit cf288d4

14 files changed

Lines changed: 256 additions & 18 deletions

File tree

build/helper/metadata_filters.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from .metadata_find import find_len_size_parameter_names
12
from .metadata_find import find_size_parameter
23
from .parameter_usage_options import ParameterUsageOptions
34

@@ -348,23 +349,26 @@ def filter_parameters(parameters, parameter_usage_options):
348349
parameters_to_use = []
349350

350351
# Filter based on options
351-
size_parameter = None
352+
ivi_dance_size_parameter = None
353+
len_size_parameter_names = set()
352354
size_twist_parameter = None
353355
# If we are being called looking for the ivi-dance, len or code param, we do not care about the size param so we do
354356
# not call back into ourselves, to avoid infinite recursion
355357
if parameter_usage_options not in [ParameterUsageOptions.IVI_DANCE_PARAMETER, ParameterUsageOptions.LEN_PARAMETER]:
356-
# Find the size parameter - we are assuming there can only be one type, either from ivi-dance or len
357-
size_parameter = find_size_parameter(filter_ivi_dance_parameters(parameters), parameters)
358-
if size_parameter is None:
359-
size_parameter = find_size_parameter(filter_len_parameters(parameters), parameters)
358+
# Determine any size parameters that should be skipped based on the presence of ivi-dance or len-sized buffers.
359+
# For ivi-dance, there is a single shared size parameter; for len, there may be multiple independent size parameters.
360+
ivi_dance_size_parameter = find_size_parameter(filter_ivi_dance_parameters(parameters), parameters)
361+
len_size_parameter_names = find_len_size_parameter_names(parameters)
360362
size_twist_parameter = find_size_parameter(filter_ivi_dance_twist_parameters(parameters), parameters, key='value_twist')
361363
for x in parameters:
362364
skip = False
363365
if x['direction'] == 'out' and options_to_use['skip_output_parameters']:
364366
skip = True
365367
if x['direction'] == 'in' and options_to_use['skip_input_parameters']:
366368
skip = True
367-
if x == size_parameter and options_to_use['skip_size_parameter']:
369+
if ivi_dance_size_parameter is not None and x == ivi_dance_size_parameter and options_to_use['skip_size_parameter']:
370+
skip = True
371+
if len_size_parameter_names and x['name'] in len_size_parameter_names and options_to_use['skip_size_parameter']:
368372
skip = True
369373
if size_twist_parameter is not None and x == size_twist_parameter and options_to_use['skip_size_parameter']:
370374
skip = True
@@ -443,18 +447,15 @@ def filter_ivi_dance_twist_parameters(parameters):
443447
def filter_len_parameters(parameters):
444448
'''Returns the len parameters of a session method if there are any. These are the parameters whose size is determined at runtime using the value of a different parameter.
445449
446-
asserts all parameters that use len reference the same parameter
450+
Note: Multiple len parameters may reference different size parameters.
447451
Args:
448452
parameters: parameters to be checked
449453
450454
Return:
451-
None if no len parameter found
452-
Parameters dict if one is found
455+
Empty list if no len parameter found
456+
List of parameter dicts if any are found
453457
'''
454458
params = filter_parameters(parameters, ParameterUsageOptions.LEN_PARAMETER)
455-
if len(params) > 0:
456-
size_param = params[0]['size']['value']
457-
assert all(x['size']['value'] == size_param for x in params)
458459
return params
459460

460461

build/helper/metadata_find.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ def find_size_parameter(parameter_list, parameters, key='value'):
4040
return None
4141

4242

43+
def find_len_size_parameter_names(parameters):
44+
'''Returns names of size parameters referenced by len-sized parameters.
45+
46+
A function may have multiple len-sized parameters, each with a different size parameter.
47+
'''
48+
len_size_parameter_names = set()
49+
len_parameters = [parameter for parameter in parameters if parameter['size']['mechanism'] == 'len']
50+
51+
for parameter in len_parameters:
52+
len_size_parameter = find_size_parameter(parameter, parameters)
53+
if len_size_parameter is not None:
54+
len_size_parameter_names.add(len_size_parameter['name'])
55+
56+
return len_size_parameter_names
57+
58+
4359
def find_custom_type(p, config):
4460
for c in config['custom_types']:
4561
if p['ctypes_type'] == c['ctypes_type']:

build/templates/_library_interpreter.py/default_method.py.mako

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
1111
ivi_dance_parameters = helper.filter_ivi_dance_parameters(parameters)
1212
ivi_dance_size_parameter = helper.find_size_parameter(ivi_dance_parameters, parameters)
13-
len_parameters = helper.filter_len_parameters(parameters)
14-
len_size_parameter = helper.find_size_parameter(len_parameters, parameters)
15-
assert ivi_dance_size_parameter is None or len_size_parameter is None
1613
1714
full_func_name = f['interpreter_name'] + method_template['method_python_name_suffix']
1815
c_func_name = config['c_function_prefix'] + f['name']

build/templates/_library_interpreter.py/initialization_method.py.mako

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
1212
ivi_dance_parameters = helper.filter_ivi_dance_parameters(parameters)
1313
ivi_dance_size_parameter = helper.find_size_parameter(ivi_dance_parameters, parameters)
14-
len_parameters = helper.filter_len_parameters(parameters)
15-
len_size_parameter = helper.find_size_parameter(len_parameters, parameters)
16-
assert ivi_dance_size_parameter is None or len_size_parameter is None
1714
1815
full_func_name = f['interpreter_name'] + method_template['method_python_name_suffix']
1916
c_func_name = config['c_function_prefix'] + f['name']
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from build.helper.metadata_filters import filter_parameters
2+
from build.helper.parameter_usage_options import ParameterUsageOptions
3+
4+
5+
def _parameter(name, direction='in', mechanism='passed-in', size_value=None):
6+
size = {'mechanism': mechanism}
7+
if size_value is not None:
8+
size['value'] = size_value
9+
10+
return {
11+
'name': name,
12+
'direction': direction,
13+
'size': size,
14+
'is_session_handle': False,
15+
'is_repeated_capability': False,
16+
'enum': None,
17+
'numpy': False,
18+
'use_in_python_api': True,
19+
'complex_array_representation': None,
20+
}
21+
22+
23+
def test_filter_parameters_mixed_usage_ivi_dance_and_len():
24+
parameters = [
25+
_parameter('ivi_size'),
26+
_parameter('out_waveform', direction='out', mechanism='ivi-dance', size_value='ivi_size'),
27+
_parameter('len_size'),
28+
_parameter('len_data', mechanism='len', size_value='len_size'),
29+
_parameter('timeout'),
30+
]
31+
32+
filtered = filter_parameters(parameters, ParameterUsageOptions.SESSION_METHOD_DECLARATION)
33+
filtered_names = [parameter['name'] for parameter in filtered]
34+
35+
assert filtered_names == ['len_data', 'timeout']
36+
37+
38+
def test_filter_parameters_multiple_len_sizes():
39+
parameters = [
40+
_parameter('len_a_size'),
41+
_parameter('len_b_size'),
42+
_parameter('len_a_data', mechanism='len', size_value='len_a_size'),
43+
_parameter('len_b_data', mechanism='len', size_value='len_b_size'),
44+
_parameter('timeout'),
45+
]
46+
47+
filtered = filter_parameters(parameters, ParameterUsageOptions.INTERPRETER_METHOD_DECLARATION)
48+
filtered_names = [parameter['name'] for parameter in filtered]
49+
50+
assert filtered_names == ['len_a_data', 'len_b_data', 'timeout']
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from build.helper.metadata_find import find_len_size_parameter_names
2+
3+
4+
def _parameter(name, mechanism='passed-in', size_value=None):
5+
size = {'mechanism': mechanism}
6+
if size_value is not None:
7+
size['value'] = size_value
8+
9+
return {
10+
'name': name,
11+
'size': size,
12+
}
13+
14+
15+
def test_find_len_size_parameter_names_multiple_sizes():
16+
parameters = [
17+
_parameter('len_a_size'),
18+
_parameter('len_b_size'),
19+
_parameter('len_a_data', mechanism='len', size_value='len_a_size'),
20+
_parameter('len_b_data', mechanism='len', size_value='len_b_size'),
21+
_parameter('timeout'),
22+
]
23+
24+
size_names = find_len_size_parameter_names(parameters)
25+
26+
assert size_names == {'len_a_size', 'len_b_size'}
27+
28+
29+
def test_find_len_size_parameter_names_empty_when_no_len_parameters():
30+
parameters = [
31+
_parameter('value'),
32+
_parameter('timeout'),
33+
]
34+
35+
size_names = find_len_size_parameter_names(parameters)
36+
37+
assert size_names == set()

generated/nifake/nifake/_grpc_stub_interpreter.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,12 @@ def multiple_array_types(self, output_array_size, input_array_of_floats, input_a
356356
)
357357
return response.output_array, response.output_array_of_fixed_length
358358

359+
def multiple_arrays_different_size(self, values_array, data_array): # noqa: N802
360+
self._invoke(
361+
self._client.MultipleArraysDifferentSize,
362+
grpc_types.MultipleArraysDifferentSizeRequest(vi=self._vi, values_array=values_array, data_array=data_array),
363+
)
364+
359365
def multiple_arrays_same_size(self, values1, values2, values3, values4): # noqa: N802
360366
self._invoke(
361367
self._client.MultipleArraysSameSize,

generated/nifake/nifake/_library.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def __init__(self, ctypes_library):
7272
self.niFake_MethodWithGrpcOnlyParam_cfunc = None
7373
self.niFake_MethodWithProtoOnlyParameter_cfunc = None
7474
self.niFake_MultipleArrayTypes_cfunc = None
75+
self.niFake_MultipleArraysDifferentSize_cfunc = None
7576
self.niFake_MultipleArraysSameSize_cfunc = None
7677
self.niFake_OneInputFunction_cfunc = None
7778
self.niFake_ParametersAreMultipleTypes_cfunc = None
@@ -477,6 +478,14 @@ def niFake_MultipleArrayTypes(self, vi, output_array_size, output_array, output_
477478
self.niFake_MultipleArrayTypes_cfunc.restype = ViStatus # noqa: F405
478479
return self.niFake_MultipleArrayTypes_cfunc(vi, output_array_size, output_array, output_array_of_fixed_length, input_array_sizes, input_array_of_floats, input_array_of_integers)
479480

481+
def niFake_MultipleArraysDifferentSize(self, vi, values_array, values_array_size, data_array, data_array_size): # noqa: N802
482+
with self._func_lock:
483+
if self.niFake_MultipleArraysDifferentSize_cfunc is None:
484+
self.niFake_MultipleArraysDifferentSize_cfunc = self._get_library_function('niFake_MultipleArraysDifferentSize')
485+
self.niFake_MultipleArraysDifferentSize_cfunc.argtypes = [ViSession, ctypes.POINTER(ViReal64), ViInt32, ctypes.POINTER(ViInt32), ViInt32] # noqa: F405
486+
self.niFake_MultipleArraysDifferentSize_cfunc.restype = ViStatus # noqa: F405
487+
return self.niFake_MultipleArraysDifferentSize_cfunc(vi, values_array, values_array_size, data_array, data_array_size)
488+
480489
def niFake_MultipleArraysSameSize(self, vi, values1, values2, values3, values4, size): # noqa: N802
481490
with self._func_lock:
482491
if self.niFake_MultipleArraysSameSize_cfunc is None:

generated/nifake/nifake/_library_interpreter.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,16 @@ def multiple_array_types(self, output_array_size, input_array_of_floats, input_a
542542
errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False)
543543
return [float(output_array_ctype[i]) for i in range(output_array_size_ctype.value)], [float(output_array_of_fixed_length_ctype[i]) for i in range(3)]
544544

545+
def multiple_arrays_different_size(self, values_array, data_array): # noqa: N802
546+
vi_ctype = _visatype.ViSession(self._vi) # case S110
547+
values_array_ctype = _get_ctypes_pointer_for_buffer(value=values_array, library_type=_visatype.ViReal64) # case B550
548+
values_array_size_ctype = _visatype.ViInt32(0 if values_array is None else len(values_array)) # case S160
549+
data_array_ctype = _get_ctypes_pointer_for_buffer(value=data_array, library_type=_visatype.ViInt32) # case B550
550+
data_array_size_ctype = _visatype.ViInt32(0 if data_array is None else len(data_array)) # case S160
551+
error_code = self._library.niFake_MultipleArraysDifferentSize(vi_ctype, values_array_ctype, values_array_size_ctype, data_array_ctype, data_array_size_ctype)
552+
errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False)
553+
return
554+
545555
def multiple_arrays_same_size(self, values1, values2, values3, values4): # noqa: N802
546556
vi_ctype = _visatype.ViSession(self._vi) # case S110
547557
values1_ctype = _get_ctypes_pointer_for_buffer(value=values1, library_type=_visatype.ViReal64) # case B550

generated/nifake/nifake/session.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,20 @@ def multiple_array_types(self, output_array_size, input_array_of_floats, input_a
14141414
output_array, output_array_of_fixed_length = self._interpreter.multiple_array_types(output_array_size, input_array_of_floats, input_array_of_integers)
14151415
return output_array, output_array_of_fixed_length
14161416

1417+
@ivi_synchronized
1418+
def multiple_arrays_different_size(self, values_array, data_array):
1419+
r'''multiple_arrays_different_size
1420+
1421+
Test method with multiple arrays that have different size parameters. This tests the length handling mechanism where different array parameters can reference different size parameters.
1422+
1423+
Args:
1424+
values_array (list of float): Array of double values with its own size parameter.
1425+
1426+
data_array (list of int): Array of integer values with a different size parameter.
1427+
1428+
'''
1429+
self._interpreter.multiple_arrays_different_size(values_array, data_array)
1430+
14171431
@ivi_synchronized
14181432
def multiple_arrays_same_size(self, values1, values2, values3, values4):
14191433
r'''multiple_arrays_same_size

0 commit comments

Comments
 (0)