diff --git a/build/helper/__init__.py b/build/helper/__init__.py index f6d8dbcfa..08ed178f1 100644 --- a/build/helper/__init__.py +++ b/build/helper/__init__.py @@ -42,6 +42,7 @@ from build.helper.metadata_add_all import add_all_metadata # noqa: F401 +from build.helper.metadata_filters import are_complex_parameters_used # noqa: F401 from build.helper.metadata_filters import filter_codegen_attributes # noqa: F401 from build.helper.metadata_filters import filter_codegen_attributes_public_only # noqa: F401 from build.helper.metadata_filters import filter_codegen_enums # noqa: F401 diff --git a/build/helper/codegen_helper.py b/build/helper/codegen_helper.py index 94dd6f3f6..86b83c476 100644 --- a/build/helper/codegen_helper.py +++ b/build/helper/codegen_helper.py @@ -256,6 +256,10 @@ def get_ctype_variable_declaration_snippet(parameter, parameters, ivi_dance_step else: module_name = '_visatype' + # Use _complextype.py file for complex parameter + if parameter['complex_type'] is not None: + module_name = '_complextype' + if parameter['is_string'] is True: definitions = _get_ctype_variable_definition_snippet_for_string(parameter, parameters, ivi_dance_step, module_name) elif parameter['is_buffer'] is True: @@ -362,7 +366,12 @@ def _get_ctype_variable_definition_snippet_for_scalar(parameter, parameters, ivi definition = '{}.{}({}) # case S150'.format(module_name, parameter['ctypes_type'], parameter['python_name']) elif corresponding_buffer_parameters and corresponding_buffer_parameters[0]['direction'] == 'in': # We are only looking at the first one to see if it is 'in'. Assumes all are the same here, assert below if not # Parameter denotes the size of another (the "corresponding") parameter. - definitions.append(parameter['ctypes_variable_name'] + ' = {0}.{1}(0 if {2} is None else len({2})) # case S160'.format(module_name, parameter['ctypes_type'], corresponding_buffer_parameters[0]['python_name'])) + # Interleaved array length is going to be double the length of number of samples. + # This is used for complex waveforms, where the real and imaginary parts are interleaved in the array. + if corresponding_buffer_parameters[0]['complex_type'] == 'interleaved': + definitions.append(parameter['ctypes_variable_name'] + ' = {0}.{1}(0 if {2} is None else len({2}) // 2) # case S160'.format(module_name, parameter['ctypes_type'], corresponding_buffer_parameters[0]['python_name'])) + else: + definitions.append(parameter['ctypes_variable_name'] + ' = {0}.{1}(0 if {2} is None else len({2})) # case S160'.format(module_name, parameter['ctypes_type'], corresponding_buffer_parameters[0]['python_name'])) else: if corresponding_buffer_parameters[0]['size']['mechanism'] == 'ivi-dance': # We are only looking at the first one. Assumes all are the same here, assert below if not # Verify all corresponding_buffer_parameters are 'out' and 'ivi-dance' @@ -426,7 +435,10 @@ def _get_ctype_variable_definition_snippet_for_buffers(parameter, parameters, iv definition = None if parameter['numpy'] is True and use_numpy_array is True: - definition = '_get_ctypes_pointer_for_buffer(value={}) # case B510'.format(parameter['python_name']) + if parameter['complex_type'] is None: + definition = '_get_ctypes_pointer_for_buffer(value={}) # case B510'.format(parameter['python_name']) + else: + definition = '_get_ctypes_pointer_for_buffer(value={}, library_type={}.{}) # case B510'.format(parameter['python_name'], module_name, parameter['ctypes_type']) elif parameter['direction'] == 'in': if custom_type is not None: definition = '_get_ctypes_pointer_for_buffer([{0}.{1}(c) for c in {2}], library_type={0}.{1}) # case B540'.format(module_name, parameter['ctypes_type'], parameter['python_name']) diff --git a/build/helper/helper.py b/build/helper/helper.py index 83c3f005b..42d295b09 100644 --- a/build/helper/helper.py +++ b/build/helper/helper.py @@ -7,25 +7,28 @@ # noqa statements because we want to format the table in a readable way _type_map = { - 'ViConstString': { 'array_type': None, 'python_type': 'str', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViString': { 'array_type': None, 'python_type': 'str', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViInt8': { 'array_type': 'b', 'python_type': 'int', 'numpy_type': 'int8', }, # noqa: E201, E202, E241 - 'ViUInt8': { 'array_type': 'B', 'python_type': 'int', 'numpy_type': 'uint8', }, # noqa: E201, E202, E241 - 'ViInt16': { 'array_type': 'h', 'python_type': 'int', 'numpy_type': 'int16', }, # noqa: E201, E202, E241 - 'ViUInt16': { 'array_type': 'H', 'python_type': 'int', 'numpy_type': 'uint16', }, # noqa: E201, E202, E241 - 'ViInt32': { 'array_type': 'l', 'python_type': 'int', 'numpy_type': 'int32', }, # noqa: E201, E202, E241 - 'ViUInt32': { 'array_type': 'L', 'python_type': 'int', 'numpy_type': 'uint32', }, # noqa: E201, E202, E241 - 'ViInt64': { 'array_type': 'q', 'python_type': 'int', 'numpy_type': 'int64', }, # noqa: E201, E202, E241 - 'ViUInt64': { 'array_type': 'Q', 'python_type': 'int', 'numpy_type': 'uint64', }, # noqa: E201, E202, E241 - 'ViReal32': { 'array_type': 'f', 'python_type': 'float', 'numpy_type': 'float32', }, # noqa: E201, E202, E241 - 'ViReal64': { 'array_type': 'd', 'python_type': 'float', 'numpy_type': 'float64', }, # noqa: E201, E202, E241 - 'ViStatus': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViSession': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViAttr': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViChar': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViChar[]': { 'array_type': None, 'python_type': 'str', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViBoolean': { 'array_type': None, 'python_type': 'bool', 'numpy_type': None, }, # noqa: E201, E202, E241 - 'ViRsrc': { 'array_type': None, 'python_type': 'str', 'numpy_type': 'bool_', }, # noqa: E201, E202, E241 + 'ViConstString': { 'array_type': None, 'python_type': 'str', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViString': { 'array_type': None, 'python_type': 'str', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViInt8': { 'array_type': 'b', 'python_type': 'int', 'numpy_type': 'int8', }, # noqa: E201, E202, E241 + 'ViUInt8': { 'array_type': 'B', 'python_type': 'int', 'numpy_type': 'uint8', }, # noqa: E201, E202, E241 + 'ViInt16': { 'array_type': 'h', 'python_type': 'int', 'numpy_type': 'int16', }, # noqa: E201, E202, E241 + 'ViUInt16': { 'array_type': 'H', 'python_type': 'int', 'numpy_type': 'uint16', }, # noqa: E201, E202, E241 + 'ViInt32': { 'array_type': 'l', 'python_type': 'int', 'numpy_type': 'int32', }, # noqa: E201, E202, E241 + 'ViUInt32': { 'array_type': 'L', 'python_type': 'int', 'numpy_type': 'uint32', }, # noqa: E201, E202, E241 + 'ViInt64': { 'array_type': 'q', 'python_type': 'int', 'numpy_type': 'int64', }, # noqa: E201, E202, E241 + 'ViUInt64': { 'array_type': 'Q', 'python_type': 'int', 'numpy_type': 'uint64', }, # noqa: E201, E202, E241 + 'ViReal32': { 'array_type': 'f', 'python_type': 'float', 'numpy_type': 'float32', }, # noqa: E201, E202, E241 + 'ViReal64': { 'array_type': 'd', 'python_type': 'float', 'numpy_type': 'float64', }, # noqa: E201, E202, E241 + 'ViStatus': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViSession': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViAttr': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViChar': { 'array_type': None, 'python_type': 'int', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViChar[]': { 'array_type': None, 'python_type': 'str', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViBoolean': { 'array_type': None, 'python_type': 'bool', 'numpy_type': None, }, # noqa: E201, E202, E241 + 'ViRsrc': { 'array_type': None, 'python_type': 'str', 'numpy_type': 'bool_', }, # noqa: E201, E202, E241 + 'NIComplexNumber': { 'array_type': None, 'python_type': None, 'numpy_type': 'complex128', }, # noqa: E201, E202, E241 + 'NIComplexNumberF32': { 'array_type': None, 'python_type': None, 'numpy_type': 'complex64', }, # noqa: E201, E202, E241 + 'NIComplexI16': { 'array_type': None, 'python_type': None, 'numpy_type': 'int16', }, # noqa: E201, E202, E241 } diff --git a/build/helper/metadata_add_all.py b/build/helper/metadata_add_all.py index ed9d836b6..a9e2f0a0d 100644 --- a/build/helper/metadata_add_all.py +++ b/build/helper/metadata_add_all.py @@ -126,6 +126,12 @@ def _add_ctypes_type(parameter, config): parameter['ctypes_type_library_call'] = module_name + parameter['ctypes_type'] +def _add_complex_type(parameter): + '''Adds a complex_type parameter to the metadata for complex numbers''' + if 'complex_type' not in parameter: + parameter['complex_type'] = None + + def _add_numpy_info(parameter, parameters, config): '''Adds the following numpy-related information: @@ -450,6 +456,7 @@ def add_all_function_metadata(functions, config): _add_python_type(p, config) _add_ctypes_variable_name(p) _add_ctypes_type(p, config) + _add_complex_type(p) _add_numpy_info(p, functions[f]['parameters'], config) _add_default_value_name(p) _add_default_value_name_for_docs(p, config['module_name']) diff --git a/build/helper/metadata_filters.py b/build/helper/metadata_filters.py index 3a4d5bb1c..cceec8ffe 100644 --- a/build/helper/metadata_filters.py +++ b/build/helper/metadata_filters.py @@ -19,6 +19,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'fixed, passed-in, len', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.SESSION_METHOD_PASSTHROUGH_CALL: { 'skip_session_handle': True, @@ -33,6 +34,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'fixed, passed-in, len', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.SESSION_NUMPY_INTO_METHOD_DECLARATION: { 'skip_session_handle': True, @@ -47,6 +49,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'fixed, passed-in', 'python_api_list': False, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.INTERPRETER_NUMPY_INTO_METHOD_DECLARATION: { 'skip_session_handle': True, @@ -61,6 +64,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'fixed, passed-in', 'python_api_list': False, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.SESSION_METHOD_CALL: { 'skip_session_handle': True, @@ -75,6 +79,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'fixed, passed-in', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.DOCUMENTATION_SESSION_METHOD: { 'skip_session_handle': True, @@ -89,6 +94,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.LIBRARY_METHOD_DECLARATION: { 'skip_session_handle': False, @@ -103,6 +109,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.LIBRARY_METHOD_CALL: { 'skip_session_handle': False, @@ -117,6 +124,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.GRPC_REQUEST_PARAMETERS: { 'skip_session_handle': False, @@ -131,6 +139,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.CTYPES_ARGTYPES: { 'skip_session_handle': False, @@ -145,6 +154,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.INTERPRETER_METHOD_DECLARATION: { 'skip_session_handle': True, @@ -159,6 +169,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'fixed, passed-in, len', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.INPUT_PARAMETERS: { 'skip_session_handle': True, @@ -173,6 +184,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.LIBRARY_OUTPUT_PARAMETERS: { 'skip_session_handle': True, @@ -187,6 +199,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.API_OUTPUT_PARAMETERS: { 'skip_session_handle': True, @@ -201,6 +214,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': False, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.API_NUMPY_OUTPUT_PARAMETERS: { 'skip_session_handle': True, @@ -215,6 +229,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': False, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.GRPC_OUTPUT_PARAMETERS: { 'skip_session_handle': True, @@ -229,6 +244,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': False, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.NUMPY_PARAMETERS: { 'skip_session_handle': True, @@ -243,6 +259,7 @@ 'skip_all_except_numpy_parameters': True, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.IVI_DANCE_PARAMETER: { 'skip_session_handle': True, @@ -257,6 +274,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'ivi-dance, ivi-dance-with-a-twist', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.LEN_PARAMETER: { 'skip_session_handle': True, @@ -271,6 +289,7 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'len', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, }, ParameterUsageOptions.INPUT_ENUM_PARAMETERS: { 'skip_session_handle': True, @@ -285,6 +304,22 @@ 'skip_all_except_numpy_parameters': False, 'mechanism': 'any', 'python_api_list': True, + 'skip_all_except_complex_type_parameters': False, + }, + ParameterUsageOptions.COMPLEX_NUMBER_PARAMETERS: { + 'skip_session_handle': True, + 'skip_input_parameters': False, + 'skip_output_parameters': False, + 'but_keep_output_numpy_array_parameters': False, + 'skip_size_parameter': False, + 'reordered_for_default_values': False, + 'skip_repeated_capability_parameter': False, + 'skip_non_enum_parameter': False, + 'skip_numpy_parameters': False, + 'skip_all_except_numpy_parameters': False, + 'mechanism': 'any', + 'python_api_list': True, + 'skip_all_except_complex_type_parameters': True, }, } @@ -349,6 +384,8 @@ def filter_parameters(parameters, parameter_usage_options): skip = False if not options_to_use['python_api_list'] and not x['use_in_python_api']: skip = True + if options_to_use['skip_all_except_complex_type_parameters'] and x['complex_type'] is None: + skip = True if not skip: parameters_to_use.append(x) @@ -451,3 +488,13 @@ def filter_codegen_enums(enums): return {k: v for k, v in enums.items() if v['codegen_method'] != 'no'} +def are_complex_parameters_used(functions): + '''Returns bool based on whether any complex parameters are used in the functions metadata.''' + are_complex_parameters_used = False + complex_parameters = [] + for k, v in functions.items(): + complex_parameters = filter_parameters(v['parameters'], ParameterUsageOptions.COMPLEX_NUMBER_PARAMETERS) + if complex_parameters != []: + are_complex_parameters_used = True + break + return are_complex_parameters_used diff --git a/build/helper/parameter_usage_options.py b/build/helper/parameter_usage_options.py index f01aa59ab..9eb9e1efd 100644 --- a/build/helper/parameter_usage_options.py +++ b/build/helper/parameter_usage_options.py @@ -62,3 +62,5 @@ class ParameterUsageOptions(AutoNumber): '''Get the len parameter''' INPUT_ENUM_PARAMETERS = () '''Get any input parameters whose type is enum''' + COMPLEX_NUMBER_PARAMETERS = () + '''Get all parameters of complex type''' diff --git a/build/templates/_complextype.py.mako b/build/templates/_complextype.py.mako new file mode 100644 index 000000000..83060bd4c --- /dev/null +++ b/build/templates/_complextype.py.mako @@ -0,0 +1,21 @@ +${template_parameters['encoding_tag']} +# This file was generated +<% + import build.helper as helper + config = template_parameters['metadata'].config + module_name = config['module_name'] +%>\ +import ctypes +import ${module_name}._visatype as _visatype + + +class NIComplexNumber(ctypes.Structure): + _fields_ = [("real", _visatype.ViReal64), ("imag", _visatype.ViReal64)] + + +class NIComplexNumberF32(ctypes.Structure): + _fields_ = [("real", _visatype.ViReal32), ("imag", _visatype.ViReal32)] + + +class NIComplexI16(ctypes.Structure): + _fields_ = [("real", _visatype.ViInt16), ("imag", _visatype.ViInt16)] diff --git a/build/templates/_library.py.mako b/build/templates/_library.py.mako index e77a7bb62..a4c242283 100644 --- a/build/templates/_library.py.mako +++ b/build/templates/_library.py.mako @@ -12,12 +12,16 @@ driver_name = config['driver_name'] functions = config['functions'] functions = helper.filter_library_functions(functions) +are_complex_parameters_used = helper.are_complex_parameters_used(functions) %>\ import ctypes import ${module_name}.errors as errors import threading +% if are_complex_parameters_used: +from ${module_name}._complextype import * # noqa: F403 +% endif from ${module_name}._visatype import * # noqa: F403,H303 % for c in config['custom_types']: diff --git a/build/templates/_library_interpreter.py.mako b/build/templates/_library_interpreter.py.mako index cf1aea315..24e5e12a4 100644 --- a/build/templates/_library_interpreter.py.mako +++ b/build/templates/_library_interpreter.py.mako @@ -12,6 +12,7 @@ driver_name = config['driver_name'] functions = config['functions'] functions = helper.filter_codegen_functions(functions) +are_complex_parameters_used = helper.are_complex_parameters_used(functions) %>\ import array @@ -20,6 +21,9 @@ import hightime # noqa: F401 % if 'SetRuntimeEnvironment' in functions: import platform +% endif +% if are_complex_parameters_used: +import ${module_name}._complextype as _complextype % endif import ${module_name}._library_singleton as _library_singleton import ${module_name}._visatype as _visatype @@ -46,7 +50,16 @@ def _get_ctypes_pointer_for_buffer(value=None, library_type=None, size=None): return ctypes.cast(addr, ctypes.POINTER(library_type)) elif str(type(value)).find("'numpy.ndarray'") != -1: import numpy + % if are_complex_parameters_used: + if library_type in (_complextype.NIComplexI16, _complextype.NIComplexNumberF32, _complextype.NIComplexNumber): + complex_dtype = numpy.dtype(library_type) + structured_array = value.view(complex_dtype) + return structured_array.ctypes.data_as(ctypes.POINTER(library_type)) + else: + return numpy.ctypeslib.as_ctypes(value) + % else: return numpy.ctypeslib.as_ctypes(value) + % endif elif isinstance(value, bytes): return ctypes.cast(value, ctypes.POINTER(library_type)) elif isinstance(value, list): diff --git a/build/templates/_matchers.py.mako b/build/templates/_matchers.py.mako index 341685d84..4c9d42768 100644 --- a/build/templates/_matchers.py.mako +++ b/build/templates/_matchers.py.mako @@ -3,8 +3,19 @@ ${template_parameters['encoding_tag']} '''Matcher classes used by unit tests in order to set mock expectations. These work well with our visatype definitions. ''' +<% +import build.helper as helper + +config = template_parameters['metadata'].config +functions = config['functions'] +functions = helper.filter_codegen_functions(functions) +are_complex_parameters_used = helper.are_complex_parameters_used(functions) +%>\ import ctypes +% if are_complex_parameters_used: +import ${template_parameters['metadata'].config['module_name']}._complextype as _complextype +% endif import ${template_parameters['metadata'].config['module_name']}._visatype as _visatype import pprint @@ -271,6 +282,59 @@ class ViReal64PointerMatcher(_PointerMatcher): _PointerMatcher.__init__(self, _visatype.ViReal64) +% if are_complex_parameters_used: +def _compare_complex_number_arrays(expected, actual): + for i in range(expected.expected_size): + expected_value = expected.expected_data[i] + actual_value = actual[i] + if expected_value.real != actual_value.real or expected_value.imag != actual_value.imag: + return False + return True + + +class NIComplexNumberPointerMatcher(_PointerMatcher): + def __init__(self, expected_data, expected_size): + _PointerMatcher.__init__(self, _complextype.NIComplexNumber) + self.expected_data = expected_data + self.expected_size = expected_size + + def __eq__(self, other): + _PointerMatcher.__eq__(self, other) + return _compare_complex_number_arrays(self, other) + + def __repr__(self): + return f"NIComplexNumberPointerMatcher({self.expected_data})" + + +class NIComplexNumberF32PointerMatcher(_PointerMatcher): + def __init__(self, expected_data, expected_size): + _PointerMatcher.__init__(self, _complextype.NIComplexNumberF32) + self.expected_data = expected_data + self.expected_size = expected_size + + def __eq__(self, other): + _PointerMatcher.__eq__(self, other) + return _compare_complex_number_arrays(self, other) + + def __repr__(self): + return f"NIComplexNumberF32PointerMatcher({self.expected_data})" + + +class NIComplexI16PointerMatcher(_PointerMatcher): + def __init__(self, expected_data, expected_size): + _PointerMatcher.__init__(self, _complextype.NIComplexI16) + self.expected_data = expected_data + self.expected_size = expected_size + + def __eq__(self, other): + _PointerMatcher.__eq__(self, other) + return _compare_complex_number_arrays(self, other) + + def __repr__(self): + return f"NIComplexI16PointerMatcher({self.expected_data})" + + +% endif # Buffers diff --git a/build/unit_tests/test_codegen_helper.py b/build/unit_tests/test_codegen_helper.py index e6b28ff27..4b5f50466 100644 --- a/build/unit_tests/test_codegen_helper.py +++ b/build/unit_tests/test_codegen_helper.py @@ -41,6 +41,7 @@ 'size': {'mechanism': 'fixed', 'value': 1}, 'type': 'ViSession', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 1 @@ -69,6 +70,7 @@ 'size': {'mechanism': 'fixed', 'value': 1}, 'type': 'ViInt64', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 2 @@ -96,6 +98,7 @@ 'size': {'mechanism': 'fixed', 'value': 256}, 'type': 'ViString', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 3 @@ -124,6 +127,7 @@ 'size': {'mechanism': 'python-code', 'value': 'self.get_array_size_for_python_code()'}, 'type': 'custom_struct', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 4 @@ -149,6 +153,7 @@ 'size': {'mechanism': 'fixed', 'value': 1}, 'type': 'ViInt32', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 5 @@ -176,6 +181,7 @@ 'size': {'mechanism': 'passed-in', 'value': 'numberOfElements'}, 'type': 'ViInt16', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 6 @@ -204,6 +210,7 @@ 'size': {'mechanism': 'fixed', 'value': 1}, 'type': 'ViInt16', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 7 @@ -231,6 +238,7 @@ 'size': {'mechanism': 'passed-in', 'value': 'numberOfElements'}, 'type': 'ViInt64', 'numpy': True, + 'complex_type': None, 'numpy_type': 'int64', 'numpy_type_library_call': 'numpy.int64', 'use_in_python_api': True, @@ -252,6 +260,7 @@ 'interpreter_method_call_snippet': 'number_of_elements_python_code', 'name': 'numberOfElementsPythonCode', 'numpy': False, + 'complex_type': None, 'python_name': 'number_of_elements_python_code', 'python_name_with_default': 'number_of_elements_python_code', 'python_name_with_doc_default': 'number_of_elements_python_code', @@ -277,6 +286,7 @@ 'interpreter_method_call_snippet': 'input', 'name': 'input', 'numpy': False, + 'complex_type': None, 'python_name': 'input', 'python_name_with_default': 'input', 'python_name_with_doc_default': 'input', @@ -305,6 +315,7 @@ 'interpreter_method_call_snippet': 'input_array', 'name': 'inputArray', 'numpy': False, + 'complex_type': None, 'python_name': 'input_array', 'python_name_with_default': 'input_array=None', 'python_name_with_doc_default': 'input_array=None', @@ -330,6 +341,7 @@ 'interpreter_method_call_snippet': 'input_array_size', 'name': 'inputArraySize', 'numpy': False, + 'complex_type': None, 'python_name': 'input_array_size', 'python_name_with_default': 'input_array_size', 'python_name_with_doc_default': 'input_array_size', @@ -355,6 +367,7 @@ 'interpreter_method_call_snippet': 'string_size', 'name': 'stringSize', 'numpy': False, + 'complex_type': None, 'python_name': 'string_size', 'python_name_with_default': 'string_size', 'python_name_with_doc_default': 'string_size', @@ -380,6 +393,7 @@ 'interpreter_method_call_snippet': 'a_string', 'name': 'aString', 'numpy': False, + 'complex_type': None, 'python_name': 'a_string', 'python_name_with_default': 'a_string', 'python_name_with_doc_default': 'a_string', @@ -406,6 +420,7 @@ 'interpreter_method_call_snippet': 'timeout', 'name': 'Timeout', 'numpy': False, + 'complex_type': None, 'python_name': 'timeout', 'python_name_with_default': 'timeout=1.0', 'python_name_with_doc_default': 'timeout=1.0', @@ -434,6 +449,7 @@ 'interpreter_method_call_snippet': 'self._repeated_capability', 'name': 'channelList', 'numpy': False, + 'complex_type': None, 'original_type': 'ViChar[]', 'python_name': 'channel_list', 'python_name_with_default': 'channel_list', @@ -460,6 +476,7 @@ 'interpreter_method_call_snippet': 'a_string', 'name': 'aString', 'numpy': False, + 'complex_type': None, 'python_name': 'a_string', 'python_name_with_default': 'a_string', 'python_name_with_doc_default': 'a_string', @@ -492,6 +509,7 @@ 'size': {'mechanism': 'len', 'value': 'array_in'}, 'type': 'custom_struct', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 18 @@ -521,6 +539,7 @@ 'size': {'mechanism': 'fixed', 'value': 256}, 'type': 'ViInt16', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 19 @@ -540,6 +559,7 @@ 'interpreter_method_call_snippet': 'a_string_2', 'name': 'aString2', 'numpy': False, + 'complex_type': None, 'python_name': 'a_string_2', 'python_name_with_default': 'a_string_2', 'python_name_with_doc_default': 'a_string_2', @@ -565,6 +585,7 @@ 'interpreter_method_call_snippet': 'a_string_3', 'name': 'aStrin3g', 'numpy': False, + 'complex_type': None, 'python_name': 'a_string_3', 'python_name_with_default': 'a_string_3', 'python_name_with_doc_default': 'a_string_3', @@ -590,6 +611,7 @@ 'interpreter_method_call_snippet': 'a_string_twist', 'name': 'aStringTwist', 'numpy': False, + 'complex_type': None, 'python_name': 'a_string_twist', 'python_name_with_default': 'a_string_twist', 'python_name_with_doc_default': 'a_string_twist', @@ -624,6 +646,7 @@ 'size': {'mechanism': 'fixed', 'value': 1}, 'type': 'ViInt64', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, { # 23 @@ -643,6 +666,7 @@ 'interpreter_method_call_snippet': 'string_size_twist', 'name': 'stringSizeTwist', 'numpy': False, + 'complex_type': None, 'python_name': 'string_size_twist', 'python_name_with_default': 'string_size_twist', 'python_name_with_doc_default': 'string_size_twist', @@ -668,6 +692,7 @@ 'interpreter_method_call_snippet': 'a_buffer', 'name': 'aBufferArray', 'numpy': False, + 'complex_type': None, 'python_name': 'a_buffer_array', 'python_name_with_default': 'a_buffer_array', 'python_name_with_doc_default': 'a_buffer_array', @@ -695,6 +720,7 @@ 'interpreter_method_call_snippet': 'a_buffer', 'name': 'aBufferList', 'numpy': False, + 'complex_type': None, 'python_name': 'a_buffer_list', 'python_name_with_default': 'a_buffer_list', 'python_name_with_doc_default': 'a_buffer_list', @@ -722,6 +748,7 @@ 'interpreter_method_call_snippet': 'a_buffer', 'name': 'aBufferTwistArray', 'numpy': False, + 'complex_type': None, 'python_name': 'a_buffer_twist_array', 'python_name_with_default': 'a_buffer_twist_array', 'python_name_with_doc_default': 'a_buffer_twist_array', @@ -749,6 +776,7 @@ 'interpreter_method_call_snippet': 'a_buffer', 'name': 'aBufferTwistList', 'numpy': False, + 'complex_type': None, 'python_name': 'a_buffer_twist_list', 'python_name_with_default': 'a_buffer_twist_list', 'python_name_with_doc_default': 'a_buffer_twist_list', @@ -779,6 +807,7 @@ 'interpreter_method_call_snippet': 'input_array_2', 'name': 'inputArray2', 'numpy': False, + 'complex_type': None, 'python_name': 'input_array_2', 'python_name_with_default': 'input_array_2=None', 'python_name_with_doc_default': 'input_array_2=None', @@ -807,6 +836,7 @@ 'interpreter_method_call_snippet': 'input_array_2', 'name': 'inputArray2', 'numpy': False, + 'complex_type': None, 'python_api_converter_name': 'convert_to_nitclk_session_num_list', 'python_name': 'input_array_2', 'python_name_with_default': 'input_array_2=None', @@ -836,6 +866,7 @@ 'interpreter_method_call_snippet': 'input_array_3', 'name': 'inputArray3', 'numpy': False, + 'complex_type': None, 'python_api_converter_name': 'convert_to_nitclk_session_num_list', 'python_name': 'input_array_3', 'python_name_with_default': 'input_array_3=None', @@ -865,6 +896,7 @@ 'interpreter_method_call_snippet': 'input_array_3', 'name': 'inputArray4', 'numpy': False, + 'complex_type': None, 'python_api_converter_name': 'convert_to_nitclk_session_num_list', 'python_name': 'input_array_4', 'python_name_with_default': 'input_array_4=None', @@ -894,6 +926,7 @@ 'interpreter_method_call_snippet': 'input_array_3', 'name': 'inputArray4', 'numpy': False, + 'complex_type': None, 'python_api_converter_name': 'convert_to_nitclk_session_num_list', 'python_name': 'input_array_4', 'python_name_with_default': 'input_array_4=None', @@ -920,6 +953,7 @@ 'interpreter_method_call_snippet': 'a_string_enum', 'name': 'aStringEnum', 'numpy': False, + 'complex_type': None, 'python_name': 'a_string_enum', 'python_name_with_default': 'a_string_enum', 'python_name_with_doc_default': 'a_string_enum', @@ -947,6 +981,7 @@ 'interpreter_method_call_snippet': 'indices', 'name': 'indices', 'numpy': False, + 'complex_type': None, 'original_type': 'ViChar[]', 'python_api_converter_name': 'convert_repeated_capabilities_without_prefix', 'python_name': 'indices', @@ -983,6 +1018,7 @@ 'size': {'mechanism': 'passed-in', 'value': 'numberOfElements'}, 'type': 'ViInt8', 'numpy': False, + 'complex_type': None, 'use_in_python_api': True, }, ] diff --git a/build/unit_tests/test_metadata_add_all.py b/build/unit_tests/test_metadata_add_all.py index 67a5750a4..f32828c64 100644 --- a/build/unit_tests/test_metadata_add_all.py +++ b/build/unit_tests/test_metadata_add_all.py @@ -259,6 +259,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'vi=self._vi', 'use_in_python_api': True, 'python_name_or_default_for_init': 'vi', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'name_ctype', @@ -292,6 +293,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'name=name', 'use_in_python_api': True, 'python_name_or_default_for_init': 'name', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'pin_data_buffer_size_ctype', @@ -328,6 +330,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'pin_data_buffer_size=pin_data_buffer_size', 'use_in_python_api': False, 'python_name_or_default_for_init': 'pin_data_buffer_size', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'python_code_input_ctype', @@ -364,6 +367,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'python_code_input=2 ** 14', 'use_in_python_api': True, 'python_name_or_default_for_init': 'python_code_input', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'None if actual_num_pin_data_ctype is None else (ctypes.pointer(actual_num_pin_data_ctype))', @@ -400,6 +404,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'actual_num_pin_data=actual_num_pin_data', 'use_in_python_api': False, 'python_name_or_default_for_init': 'actual_num_pin_data', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'expected_pin_states_ctype', @@ -438,6 +443,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'expected_pin_states=expected_pin_states', 'use_in_python_api': True, 'python_name_or_default_for_init': 'expected_pin_states', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'custom_type_input_ctype', @@ -474,6 +480,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'custom_type_input=custom_type_input._create_copy(grpc_types.CustomStruct)', 'use_in_python_api': True, 'python_name_or_default_for_init': 'custom_type_input', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'None if custom_type_output_ctype is None else (ctypes.pointer(custom_type_output_ctype))', @@ -510,6 +517,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'custom_type_output=custom_type_output._create_copy(grpc_types.CustomStruct)', 'use_in_python_api': True, 'python_name_or_default_for_init': 'custom_type_output', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'custom_type_without_struct_prefix_input_ctype', @@ -546,6 +554,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'custom_type_without_struct_prefix_input=custom_type_without_struct_prefix_input._create_copy(grpc_types.CustomStruct)', 'use_in_python_api': True, 'python_name_or_default_for_init': 'custom_type_without_struct_prefix_input', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'None if custom_type_without_struct_prefix_output_ctype is None else (ctypes.pointer(custom_type_without_struct_prefix_output_ctype))', @@ -582,6 +591,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'custom_type_without_struct_prefix_output=custom_type_without_struct_prefix_output._create_copy(grpc_types.CustomStruct)', 'use_in_python_api': True, 'python_name_or_default_for_init': 'custom_type_without_struct_prefix_output', + 'complex_type': None, }, ], 'python_name': 'make_a_foo', @@ -629,6 +639,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'vi=self._vi', 'use_in_python_api': True, 'python_name_or_default_for_init': 'vi', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'status_ctype', @@ -665,6 +676,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'status=status', 'use_in_python_api': True, 'python_name_or_default_for_init': 'status', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'data_buffer_size_ctype', @@ -701,6 +713,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'data_buffer_size=data_buffer_size', 'use_in_python_api': False, 'python_name_or_default_for_init': 'data_buffer_size', + 'complex_type': None, }, { 'ctypes_method_call_snippet': 'data_ctype', @@ -738,6 +751,7 @@ def _compare_dicts(actual, expected): 'grpc_request_snippet': 'data=data', 'use_in_python_api': True, 'python_name_or_default_for_init': 'data', + 'complex_type': None, }, ], 'documentation': { diff --git a/generated/nifake/nifake/_complextype.py b/generated/nifake/nifake/_complextype.py new file mode 100644 index 000000000..e23fa1b7e --- /dev/null +++ b/generated/nifake/nifake/_complextype.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# This file was generated +import ctypes +import nifake._visatype as _visatype + + +class NIComplexNumber(ctypes.Structure): + _fields_ = [("real", _visatype.ViReal64), ("imag", _visatype.ViReal64)] + + +class NIComplexNumberF32(ctypes.Structure): + _fields_ = [("real", _visatype.ViReal32), ("imag", _visatype.ViReal32)] + + +class NIComplexI16(ctypes.Structure): + _fields_ = [("real", _visatype.ViInt16), ("imag", _visatype.ViInt16)] diff --git a/generated/nifake/nifake/_grpc_stub_interpreter.py b/generated/nifake/nifake/_grpc_stub_interpreter.py index ee8d29c04..489da1538 100644 --- a/generated/nifake/nifake/_grpc_stub_interpreter.py +++ b/generated/nifake/nifake/_grpc_stub_interpreter.py @@ -489,6 +489,15 @@ def write_waveform(self, waveform): # noqa: N802 def write_waveform_numpy(self, waveform): # noqa: N802 raise NotImplementedError('numpy-specific methods are not supported over gRPC') + def write_waveform_numpy_complex128(self, waveform_data_array): # noqa: N802 + raise NotImplementedError('numpy-specific methods are not supported over gRPC') + + def write_waveform_numpy_complex64(self, waveform_data_array): # noqa: N802 + raise NotImplementedError('numpy-specific methods are not supported over gRPC') + + def write_waveform_numpy_complex_interleaved_i16(self, waveform_data_array): # noqa: N802 + raise NotImplementedError('numpy-specific methods are not supported over gRPC') + def close(self): # noqa: N802 self._invoke( self._client.Close, diff --git a/generated/nifake/nifake/_library.py b/generated/nifake/nifake/_library.py index 5fef6060e..e9e6e94d6 100644 --- a/generated/nifake/nifake/_library.py +++ b/generated/nifake/nifake/_library.py @@ -5,6 +5,7 @@ import nifake.errors as errors import threading +from nifake._complextype import * # noqa: F403 from nifake._visatype import * # noqa: F403,H303 import nifake.custom_struct as custom_struct # noqa: F401 @@ -92,6 +93,9 @@ def __init__(self, ctypes_library): self.niFake_UnlockSession_cfunc = None self.niFake_Use64BitNumber_cfunc = None self.niFake_WriteWaveform_cfunc = None + self.niFake_WriteWaveformNumpyComplex128_cfunc = None + self.niFake_WriteWaveformNumpyComplex64_cfunc = None + self.niFake_WriteWaveformNumpyComplexInterleavedI16_cfunc = None self.niFake_close_cfunc = None self.niFake_error_message_cfunc = None self.niFake_self_test_cfunc = None @@ -639,6 +643,30 @@ def niFake_WriteWaveform(self, vi, number_of_samples, waveform): # noqa: N802 self.niFake_WriteWaveform_cfunc.restype = ViStatus # noqa: F405 return self.niFake_WriteWaveform_cfunc(vi, number_of_samples, waveform) + def niFake_WriteWaveformNumpyComplex128(self, vi, number_of_samples, waveform_data_array): # noqa: N802 + with self._func_lock: + if self.niFake_WriteWaveformNumpyComplex128_cfunc is None: + self.niFake_WriteWaveformNumpyComplex128_cfunc = self._get_library_function('niFake_WriteWaveformNumpyComplex128') + self.niFake_WriteWaveformNumpyComplex128_cfunc.argtypes = [ViSession, ViInt32, ctypes.POINTER(NIComplexNumber)] # noqa: F405 + self.niFake_WriteWaveformNumpyComplex128_cfunc.restype = ViStatus # noqa: F405 + return self.niFake_WriteWaveformNumpyComplex128_cfunc(vi, number_of_samples, waveform_data_array) + + def niFake_WriteWaveformNumpyComplex64(self, vi, number_of_samples, waveform_data_array): # noqa: N802 + with self._func_lock: + if self.niFake_WriteWaveformNumpyComplex64_cfunc is None: + self.niFake_WriteWaveformNumpyComplex64_cfunc = self._get_library_function('niFake_WriteWaveformNumpyComplex64') + self.niFake_WriteWaveformNumpyComplex64_cfunc.argtypes = [ViSession, ViInt32, ctypes.POINTER(NIComplexNumberF32)] # noqa: F405 + self.niFake_WriteWaveformNumpyComplex64_cfunc.restype = ViStatus # noqa: F405 + return self.niFake_WriteWaveformNumpyComplex64_cfunc(vi, number_of_samples, waveform_data_array) + + def niFake_WriteWaveformNumpyComplexInterleavedI16(self, vi, number_of_samples, waveform_data_array): # noqa: N802 + with self._func_lock: + if self.niFake_WriteWaveformNumpyComplexInterleavedI16_cfunc is None: + self.niFake_WriteWaveformNumpyComplexInterleavedI16_cfunc = self._get_library_function('niFake_WriteWaveformNumpyComplexInterleavedI16') + self.niFake_WriteWaveformNumpyComplexInterleavedI16_cfunc.argtypes = [ViSession, ViInt32, ctypes.POINTER(NIComplexI16)] # noqa: F405 + self.niFake_WriteWaveformNumpyComplexInterleavedI16_cfunc.restype = ViStatus # noqa: F405 + return self.niFake_WriteWaveformNumpyComplexInterleavedI16_cfunc(vi, number_of_samples, waveform_data_array) + def niFake_close(self, vi): # noqa: N802 with self._func_lock: if self.niFake_close_cfunc is None: diff --git a/generated/nifake/nifake/_library_interpreter.py b/generated/nifake/nifake/_library_interpreter.py index d2715505a..799c39772 100644 --- a/generated/nifake/nifake/_library_interpreter.py +++ b/generated/nifake/nifake/_library_interpreter.py @@ -6,6 +6,7 @@ import hightime # noqa: F401 import platform +import nifake._complextype as _complextype import nifake._library_singleton as _library_singleton import nifake._visatype as _visatype import nifake.enums as enums # noqa: F401 @@ -29,7 +30,12 @@ def _get_ctypes_pointer_for_buffer(value=None, library_type=None, size=None): return ctypes.cast(addr, ctypes.POINTER(library_type)) elif str(type(value)).find("'numpy.ndarray'") != -1: import numpy - return numpy.ctypeslib.as_ctypes(value) + if library_type in (_complextype.NIComplexI16, _complextype.NIComplexNumberF32, _complextype.NIComplexNumber): + complex_dtype = numpy.dtype(library_type) + structured_array = value.view(complex_dtype) + return structured_array.ctypes.data_as(ctypes.POINTER(library_type)) + else: + return numpy.ctypeslib.as_ctypes(value) elif isinstance(value, bytes): return ctypes.cast(value, ctypes.POINTER(library_type)) elif isinstance(value, list): @@ -732,6 +738,30 @@ def write_waveform_numpy(self, waveform): # noqa: N802 errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) return + def write_waveform_numpy_complex128(self, waveform_data_array): # noqa: N802 + vi_ctype = _visatype.ViSession(self._vi) # case S110 + number_of_samples_ctype = _visatype.ViInt32(0 if waveform_data_array is None else len(waveform_data_array)) # case S160 + waveform_data_array_ctype = _get_ctypes_pointer_for_buffer(value=waveform_data_array, library_type=_complextype.NIComplexNumber) # case B510 + error_code = self._library.niFake_WriteWaveformNumpyComplex128(vi_ctype, number_of_samples_ctype, waveform_data_array_ctype) + errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) + return + + def write_waveform_numpy_complex64(self, waveform_data_array): # noqa: N802 + vi_ctype = _visatype.ViSession(self._vi) # case S110 + number_of_samples_ctype = _visatype.ViInt32(0 if waveform_data_array is None else len(waveform_data_array)) # case S160 + waveform_data_array_ctype = _get_ctypes_pointer_for_buffer(value=waveform_data_array, library_type=_complextype.NIComplexNumberF32) # case B510 + error_code = self._library.niFake_WriteWaveformNumpyComplex64(vi_ctype, number_of_samples_ctype, waveform_data_array_ctype) + errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) + return + + def write_waveform_numpy_complex_interleaved_i16(self, waveform_data_array): # noqa: N802 + vi_ctype = _visatype.ViSession(self._vi) # case S110 + number_of_samples_ctype = _visatype.ViInt32(0 if waveform_data_array is None else len(waveform_data_array) // 2) # case S160 + waveform_data_array_ctype = _get_ctypes_pointer_for_buffer(value=waveform_data_array, library_type=_complextype.NIComplexI16) # case B510 + error_code = self._library.niFake_WriteWaveformNumpyComplexInterleavedI16(vi_ctype, number_of_samples_ctype, waveform_data_array_ctype) + errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) + return + def close(self): # noqa: N802 vi_ctype = _visatype.ViSession(self._vi) # case S110 error_code = self._library.niFake_close(vi_ctype) diff --git a/generated/nifake/nifake/session.py b/generated/nifake/nifake/session.py index 6f80d4858..c81870530 100644 --- a/generated/nifake/nifake/session.py +++ b/generated/nifake/nifake/session.py @@ -1670,6 +1670,66 @@ def write_waveform_numpy(self, waveform): raise TypeError('waveform must be numpy.ndarray of dtype=float64, is ' + str(waveform.dtype)) self._interpreter.write_waveform_numpy(waveform) + @ivi_synchronized + def write_waveform_numpy_complex128(self, waveform_data_array): + r'''write_waveform_numpy_complex128 + + A method that writes a waveform of numpy complex128 numbers + + Args: + waveform_data_array (numpy.array(dtype=numpy.complex128)): Specifies the array of data to load into the waveform. Array should be numberOfSamples big. + + ''' + import numpy + + if type(waveform_data_array) is not numpy.ndarray: + raise TypeError('waveform_data_array must be {0}, is {1}'.format(numpy.ndarray, type(waveform_data_array))) + if numpy.isfortran(waveform_data_array) is True: + raise TypeError('waveform_data_array must be in C-order') + if waveform_data_array.dtype is not numpy.dtype('complex128'): + raise TypeError('waveform_data_array must be numpy.ndarray of dtype=complex128, is ' + str(waveform_data_array.dtype)) + self._interpreter.write_waveform_numpy_complex128(waveform_data_array) + + @ivi_synchronized + def write_waveform_numpy_complex64(self, waveform_data_array): + r'''write_waveform_numpy_complex64 + + A method that writes a waveform of numpy complex64 numbers. + + Args: + waveform_data_array (numpy.array(dtype=numpy.complex64)): Specifies the array of data to load into the waveform. Array should be numberOfSamples big. + + ''' + import numpy + + if type(waveform_data_array) is not numpy.ndarray: + raise TypeError('waveform_data_array must be {0}, is {1}'.format(numpy.ndarray, type(waveform_data_array))) + if numpy.isfortran(waveform_data_array) is True: + raise TypeError('waveform_data_array must be in C-order') + if waveform_data_array.dtype is not numpy.dtype('complex64'): + raise TypeError('waveform_data_array must be numpy.ndarray of dtype=complex64, is ' + str(waveform_data_array.dtype)) + self._interpreter.write_waveform_numpy_complex64(waveform_data_array) + + @ivi_synchronized + def write_waveform_numpy_complex_interleaved_i16(self, waveform_data_array): + r'''write_waveform_numpy_complex_interleaved_i16 + + A method that writes a waveform of numpy complex i16 numbers. + + Args: + waveform_data_array (numpy.array(dtype=numpy.int16)): Specifies the array of data to load into the waveform. Array should be numberOfSamples big. + + ''' + import numpy + + if type(waveform_data_array) is not numpy.ndarray: + raise TypeError('waveform_data_array must be {0}, is {1}'.format(numpy.ndarray, type(waveform_data_array))) + if numpy.isfortran(waveform_data_array) is True: + raise TypeError('waveform_data_array must be in C-order') + if waveform_data_array.dtype is not numpy.dtype('int16'): + raise TypeError('waveform_data_array must be numpy.ndarray of dtype=int16, is ' + str(waveform_data_array.dtype)) + self._interpreter.write_waveform_numpy_complex_interleaved_i16(waveform_data_array) + def _close(self): r'''_close diff --git a/generated/nifake/nifake/unit_tests/_matchers.py b/generated/nifake/nifake/unit_tests/_matchers.py index 6843dd5ec..f95383417 100644 --- a/generated/nifake/nifake/unit_tests/_matchers.py +++ b/generated/nifake/nifake/unit_tests/_matchers.py @@ -5,6 +5,7 @@ ''' import ctypes +import nifake._complextype as _complextype import nifake._visatype as _visatype import pprint @@ -271,6 +272,57 @@ def __init__(self): _PointerMatcher.__init__(self, _visatype.ViReal64) +def _compare_complex_number_arrays(expected, actual): + for i in range(expected.expected_size): + expected_value = expected.expected_data[i] + actual_value = actual[i] + if expected_value.real != actual_value.real or expected_value.imag != actual_value.imag: + return False + return True + + +class NIComplexNumberPointerMatcher(_PointerMatcher): + def __init__(self, expected_data, expected_size): + _PointerMatcher.__init__(self, _complextype.NIComplexNumber) + self.expected_data = expected_data + self.expected_size = expected_size + + def __eq__(self, other): + _PointerMatcher.__eq__(self, other) + return _compare_complex_number_arrays(self, other) + + def __repr__(self): + return f"NIComplexNumberPointerMatcher({self.expected_data})" + + +class NIComplexNumberF32PointerMatcher(_PointerMatcher): + def __init__(self, expected_data, expected_size): + _PointerMatcher.__init__(self, _complextype.NIComplexNumberF32) + self.expected_data = expected_data + self.expected_size = expected_size + + def __eq__(self, other): + _PointerMatcher.__eq__(self, other) + return _compare_complex_number_arrays(self, other) + + def __repr__(self): + return f"NIComplexNumberF32PointerMatcher({self.expected_data})" + + +class NIComplexI16PointerMatcher(_PointerMatcher): + def __init__(self, expected_data, expected_size): + _PointerMatcher.__init__(self, _complextype.NIComplexI16) + self.expected_data = expected_data + self.expected_size = expected_size + + def __eq__(self, other): + _PointerMatcher.__eq__(self, other) + return _compare_complex_number_arrays(self, other) + + def __repr__(self): + return f"NIComplexI16PointerMatcher({self.expected_data})" + + # Buffers diff --git a/generated/nifake/nifake/unit_tests/_mock_helper.py b/generated/nifake/nifake/unit_tests/_mock_helper.py index fe2a60669..7943d3f93 100644 --- a/generated/nifake/nifake/unit_tests/_mock_helper.py +++ b/generated/nifake/nifake/unit_tests/_mock_helper.py @@ -210,6 +210,12 @@ def __init__(self): self._defaults['Use64BitNumber']['output'] = None self._defaults['WriteWaveform'] = {} self._defaults['WriteWaveform']['return'] = 0 + self._defaults['WriteWaveformNumpyComplex128'] = {} + self._defaults['WriteWaveformNumpyComplex128']['return'] = 0 + self._defaults['WriteWaveformNumpyComplex64'] = {} + self._defaults['WriteWaveformNumpyComplex64']['return'] = 0 + self._defaults['WriteWaveformNumpyComplexInterleavedI16'] = {} + self._defaults['WriteWaveformNumpyComplexInterleavedI16']['return'] = 0 self._defaults['close'] = {} self._defaults['close']['return'] = 0 self._defaults['error_message'] = {} @@ -955,6 +961,21 @@ def niFake_WriteWaveform(self, vi, number_of_samples, waveform): # noqa: N802 return self._defaults['WriteWaveform']['return'] return self._defaults['WriteWaveform']['return'] + def niFake_WriteWaveformNumpyComplex128(self, vi, number_of_samples, waveform_data_array): # noqa: N802 + if self._defaults['WriteWaveformNumpyComplex128']['return'] != 0: + return self._defaults['WriteWaveformNumpyComplex128']['return'] + return self._defaults['WriteWaveformNumpyComplex128']['return'] + + def niFake_WriteWaveformNumpyComplex64(self, vi, number_of_samples, waveform_data_array): # noqa: N802 + if self._defaults['WriteWaveformNumpyComplex64']['return'] != 0: + return self._defaults['WriteWaveformNumpyComplex64']['return'] + return self._defaults['WriteWaveformNumpyComplex64']['return'] + + def niFake_WriteWaveformNumpyComplexInterleavedI16(self, vi, number_of_samples, waveform_data_array): # noqa: N802 + if self._defaults['WriteWaveformNumpyComplexInterleavedI16']['return'] != 0: + return self._defaults['WriteWaveformNumpyComplexInterleavedI16']['return'] + return self._defaults['WriteWaveformNumpyComplexInterleavedI16']['return'] + def niFake_close(self, vi): # noqa: N802 if self._defaults['close']['return'] != 0: return self._defaults['close']['return'] @@ -1129,6 +1150,12 @@ def set_side_effects_and_return_values(self, mock_library): mock_library.niFake_Use64BitNumber.return_value = 0 mock_library.niFake_WriteWaveform.side_effect = MockFunctionCallError("niFake_WriteWaveform") mock_library.niFake_WriteWaveform.return_value = 0 + mock_library.niFake_WriteWaveformNumpyComplex128.side_effect = MockFunctionCallError("niFake_WriteWaveformNumpyComplex128") + mock_library.niFake_WriteWaveformNumpyComplex128.return_value = 0 + mock_library.niFake_WriteWaveformNumpyComplex64.side_effect = MockFunctionCallError("niFake_WriteWaveformNumpyComplex64") + mock_library.niFake_WriteWaveformNumpyComplex64.return_value = 0 + mock_library.niFake_WriteWaveformNumpyComplexInterleavedI16.side_effect = MockFunctionCallError("niFake_WriteWaveformNumpyComplexInterleavedI16") + mock_library.niFake_WriteWaveformNumpyComplexInterleavedI16.return_value = 0 mock_library.niFake_close.side_effect = MockFunctionCallError("niFake_close") mock_library.niFake_close.return_value = 0 mock_library.niFake_error_message.side_effect = MockFunctionCallError("niFake_error_message") diff --git a/generated/nifake/nifake/unit_tests/test_library_interpreter.py b/generated/nifake/nifake/unit_tests/test_library_interpreter.py index 4298bcb56..bf9542186 100644 --- a/generated/nifake/nifake/unit_tests/test_library_interpreter.py +++ b/generated/nifake/nifake/unit_tests/test_library_interpreter.py @@ -843,6 +843,62 @@ def test_import_attribute_configuration_buffer_str(self): interpreter.import_attribute_configuration_buffer(configuration) self.patched_library.niFake_ImportAttributeConfigurationBuffer.assert_called_once_with(_matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), _matchers.ViInt32Matcher(len(configuration)), _matchers.ViInt8BufferMatcher(expected_list)) + def test_write_waveform_numpy_complex128_valid_input(self): + from nifake._complextype import NIComplexNumber + + waveform_data = numpy.full(1000, 0.707 + 0.707j, dtype=numpy.complex128) + number_of_samples = len(waveform_data) + + waveform_data_ctypes = (NIComplexNumber * number_of_samples)( + *[NIComplexNumber(real=0.707, imag=0.707) for _ in range(number_of_samples)] + ) + waveform_data_pointer = ctypes.cast(waveform_data_ctypes, ctypes.POINTER(NIComplexNumber)) + self.patched_library.niFake_WriteWaveformNumpyComplex128.side_effect = self.side_effects_helper.niFake_WriteWaveformNumpyComplex128 + interpreter = self.get_initialized_library_interpreter() + interpreter.write_waveform_numpy_complex128(waveform_data) + self.patched_library.niFake_WriteWaveformNumpyComplex128.assert_called_once_with( + _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), + _matchers.ViInt32Matcher(number_of_samples), + _matchers.NIComplexNumberPointerMatcher(waveform_data_pointer, number_of_samples) + ) + + def test_write_waveform_numpy_complex64_valid_input(self): + from nifake._complextype import NIComplexNumberF32 + + waveform_data = numpy.full(1000, 0.707 + 0.707j, dtype=numpy.complex64) + number_of_samples = len(waveform_data) + + waveform_data_ctypes = (NIComplexNumberF32 * number_of_samples)( + *[NIComplexNumberF32(real=0.707, imag=0.707) for _ in range(number_of_samples)] + ) + waveform_data_pointer = ctypes.cast(waveform_data_ctypes, ctypes.POINTER(NIComplexNumberF32)) + self.patched_library.niFake_WriteWaveformNumpyComplex64.side_effect = self.side_effects_helper.niFake_WriteWaveformNumpyComplex64 + interpreter = self.get_initialized_library_interpreter() + interpreter.write_waveform_numpy_complex64(waveform_data) + self.patched_library.niFake_WriteWaveformNumpyComplex64.assert_called_once_with( + _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), + _matchers.ViInt32Matcher(number_of_samples), + _matchers.NIComplexNumberF32PointerMatcher(waveform_data_pointer, number_of_samples) + ) + + def test_write_waveform_numpy_complex_interleaved_i16_valid_input(self): + from nifake._complextype import NIComplexI16 + + waveform_data = numpy.array([32767, 0] * 1000, dtype=numpy.int16) + number_of_samples = len(waveform_data) // 2 + waveform_data_ctypes = (NIComplexI16 * number_of_samples)( + *[NIComplexI16(real=32767, imag=0) for _ in range(number_of_samples)] + ) + waveform_data_pointer = ctypes.cast(waveform_data_ctypes, ctypes.POINTER(NIComplexI16)) + self.patched_library.niFake_WriteWaveformNumpyComplexInterleavedI16.side_effect = self.side_effects_helper.niFake_WriteWaveformNumpyComplexInterleavedI16 + interpreter = self.get_initialized_library_interpreter() + interpreter.write_waveform_numpy_complex_interleaved_i16(waveform_data) + self.patched_library.niFake_WriteWaveformNumpyComplexInterleavedI16.assert_called_once_with( + _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), + _matchers.ViInt32Matcher(number_of_samples), + _matchers.NIComplexI16PointerMatcher(waveform_data_pointer, number_of_samples) + ) + def test_matcher_prints(self): assert _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST).__repr__() == "ViSessionMatcher(" + str(nifake._visatype.ViSession) + ", 42)" assert _matchers.ViAttrMatcher(SESSION_NUM_FOR_TEST).__repr__() == "ViAttrMatcher(" + str(nifake._visatype.ViAttr) + ", 42)" diff --git a/generated/nifake/nifake/unit_tests/test_session.py b/generated/nifake/nifake/unit_tests/test_session.py index 7f243dcf8..16af4e81a 100644 --- a/generated/nifake/nifake/unit_tests/test_session.py +++ b/generated/nifake/nifake/unit_tests/test_session.py @@ -837,6 +837,33 @@ def test_return_timedeltas(self): assert returned_timedeltas == expected_timedeltas self.patched_library_interpreter.return_list_of_durations_in_seconds.assert_called_once_with(len(time_values)) + def test_session_write_waveform_numpy_complex64_invalid_dtype(self): + invalid_waveform_data = numpy.full(10, 1.0 + 1.0j, dtype=numpy.complex128) + expected_error_message = "waveform_data_array must be numpy.ndarray of dtype=complex64, is complex128" + import pytest + with nifake.Session('dev1') as session: + with pytest.raises(TypeError) as exc_info: + session.write_waveform_numpy_complex64(invalid_waveform_data) + assert str(exc_info.value) == expected_error_message + + def test_session_write_waveform_numpy_complex128_invalid_dtype(self): + invalid_waveform_data = numpy.full(10, 1.0 + 1.0j, dtype=numpy.complex64) + expected_error_message = "waveform_data_array must be numpy.ndarray of dtype=complex128, is complex64" + import pytest + with nifake.Session('dev1') as session: + with pytest.raises(TypeError) as exc_info: + session.write_waveform_numpy_complex128(invalid_waveform_data) + assert str(exc_info.value) == expected_error_message + + def test_session_write_waveform_numpy_complex_interleaved_i16_invalid_dtype(self): + invalid_waveform_data = numpy.full(10, 1.0 + 1.0j, dtype=numpy.complex64) + expected_error_message = "waveform_data_array must be numpy.ndarray of dtype=int16, is complex64" + import pytest + with nifake.Session('dev1') as session: + with pytest.raises(TypeError) as exc_info: + session.write_waveform_numpy_complex_interleaved_i16(invalid_waveform_data) + assert str(exc_info.value) == expected_error_message + class TestGrpcSession: diff --git a/src/nifake/metadata/functions.py b/src/nifake/metadata/functions.py index 24d8ebd8c..210bf444f 100644 --- a/src/nifake/metadata/functions.py +++ b/src/nifake/metadata/functions.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# This file is generated from NI-FAKE API metadata version 24.8.0f100 +# This file is generated from NI-FAKE API metadata version 25.5.0d9999 functions = { 'Abort': { 'codegen_method': 'public', @@ -2797,6 +2797,171 @@ ], 'returns': 'ViStatus' }, + 'WriteWaveformNumpyComplex64': { + 'codegen_method': 'public', + 'documentation': { + 'description': 'A function that writes a waveform of numpy complex64 numbers.' + }, + 'included_in_proto': False, + 'is_error_handling': False, + 'method_templates': [ + { + 'documentation_filename': 'numpy_method', + 'library_interpreter_filename': 'numpy_write_method', + 'method_python_name_suffix': '', + 'session_filename': 'numpy_write_method' + } + ], + 'parameters': [ + { + 'direction': 'in', + 'documentation': { + 'description': 'Identifies a particular instrument session.' + }, + 'name': 'vi', + 'type': 'ViSession', + 'use_array': False, + 'use_in_python_api': True + }, + { + 'direction': 'in', + 'documentation': { + 'description': 'Specifies the number of samples in the message signal.' + }, + 'name': 'numberOfSamples', + 'type': 'ViInt32', + 'use_array': False, + 'use_in_python_api': False + }, + { + 'complex_type': 'numpy', + 'direction': 'in', + 'documentation': { + 'description': 'Specifies the array of data to load into the waveform. Array should be numberOfSamples big.' + }, + 'name': 'waveformDataArray', + 'numpy': True, + 'size': { + 'mechanism': 'len', + 'value': 'numberOfSamples' + }, + 'type': 'NIComplexNumberF32[]', + 'use_in_python_api': True, + 'use_numpy_array': True + } + ], + 'returns': 'ViStatus' + }, + 'WriteWaveformNumpyComplex128': { + 'codegen_method': 'public', + 'documentation': { + 'description': 'A function that writes a waveform of numpy complex128 numbers' + }, + 'included_in_proto': False, + 'is_error_handling': False, + 'method_templates': [ + { + 'documentation_filename': 'numpy_method', + 'library_interpreter_filename': 'numpy_write_method', + 'method_python_name_suffix': '', + 'session_filename': 'numpy_write_method' + } + ], + 'parameters': [ + { + 'direction': 'in', + 'documentation': { + 'description': 'Identifies a particular instrument session.' + }, + 'name': 'vi', + 'type': 'ViSession', + 'use_array': False, + 'use_in_python_api': True + }, + { + 'direction': 'in', + 'documentation': { + 'description': 'Specifies the number of samples in the message signal.' + }, + 'name': 'numberOfSamples', + 'type': 'ViInt32', + 'use_array': False, + 'use_in_python_api': False + }, + { + 'complex_type': 'numpy', + 'direction': 'in', + 'documentation': { + 'description': 'Specifies the array of data to load into the waveform. Array should be numberOfSamples big.' + }, + 'name': 'waveformDataArray', + 'numpy': True, + 'size': { + 'mechanism': 'len', + 'value': 'numberOfSamples' + }, + 'type': 'NIComplexNumber[]', + 'use_in_python_api': True, + 'use_numpy_array': True + } + ], + 'returns': 'ViStatus' + }, + 'WriteWaveformNumpyComplexInterleavedI16': { + 'codegen_method': 'public', + 'documentation': { + 'description': 'A function that writes a waveform of numpy complex i16 numbers.' + }, + 'included_in_proto': False, + 'is_error_handling': False, + 'method_templates': [ + { + 'documentation_filename': 'numpy_method', + 'library_interpreter_filename': 'numpy_write_method', + 'method_python_name_suffix': '', + 'session_filename': 'numpy_write_method' + } + ], + 'parameters': [ + { + 'direction': 'in', + 'documentation': { + 'description': 'Identifies a particular instrument session.' + }, + 'name': 'vi', + 'type': 'ViSession', + 'use_array': False, + 'use_in_python_api': True + }, + { + 'direction': 'in', + 'documentation': { + 'description': 'Specifies the number of samples in the message signal.' + }, + 'name': 'numberOfSamples', + 'type': 'ViInt32', + 'use_array': False, + 'use_in_python_api': False + }, + { + 'complex_type': 'interleaved', + 'direction': 'in', + 'documentation': { + 'description': 'Specifies the array of data to load into the waveform. Array should be numberOfSamples big.' + }, + 'name': 'waveformDataArray', + 'numpy': True, + 'size': { + 'mechanism': 'len', + 'value': 'numberOfSamples' + }, + 'type': 'NIComplexI16[]', + 'use_in_python_api': True, + 'use_numpy_array': True + } + ], + 'returns': 'ViStatus' + }, 'close': { 'codegen_method': 'private', 'documentation': { diff --git a/src/nifake/nifake.mak b/src/nifake/nifake.mak index a9f456f55..85386b617 100644 --- a/src/nifake/nifake.mak +++ b/src/nifake/nifake.mak @@ -2,7 +2,7 @@ include $(BUILD_HELPER_DIR)/defines.mak -MODULE_FILES_TO_GENERATE := $(DEFAULT_PY_FILES_TO_GENERATE) +MODULE_FILES_TO_GENERATE := $(DEFAULT_PY_FILES_TO_GENERATE) _complextype.py MODULE_FILES_TO_COPY := $(DEFAULT_PY_FILES_TO_COPY) diff --git a/src/nifake/unit_tests/test_library_interpreter.py b/src/nifake/unit_tests/test_library_interpreter.py index 4298bcb56..bf9542186 100644 --- a/src/nifake/unit_tests/test_library_interpreter.py +++ b/src/nifake/unit_tests/test_library_interpreter.py @@ -843,6 +843,62 @@ def test_import_attribute_configuration_buffer_str(self): interpreter.import_attribute_configuration_buffer(configuration) self.patched_library.niFake_ImportAttributeConfigurationBuffer.assert_called_once_with(_matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), _matchers.ViInt32Matcher(len(configuration)), _matchers.ViInt8BufferMatcher(expected_list)) + def test_write_waveform_numpy_complex128_valid_input(self): + from nifake._complextype import NIComplexNumber + + waveform_data = numpy.full(1000, 0.707 + 0.707j, dtype=numpy.complex128) + number_of_samples = len(waveform_data) + + waveform_data_ctypes = (NIComplexNumber * number_of_samples)( + *[NIComplexNumber(real=0.707, imag=0.707) for _ in range(number_of_samples)] + ) + waveform_data_pointer = ctypes.cast(waveform_data_ctypes, ctypes.POINTER(NIComplexNumber)) + self.patched_library.niFake_WriteWaveformNumpyComplex128.side_effect = self.side_effects_helper.niFake_WriteWaveformNumpyComplex128 + interpreter = self.get_initialized_library_interpreter() + interpreter.write_waveform_numpy_complex128(waveform_data) + self.patched_library.niFake_WriteWaveformNumpyComplex128.assert_called_once_with( + _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), + _matchers.ViInt32Matcher(number_of_samples), + _matchers.NIComplexNumberPointerMatcher(waveform_data_pointer, number_of_samples) + ) + + def test_write_waveform_numpy_complex64_valid_input(self): + from nifake._complextype import NIComplexNumberF32 + + waveform_data = numpy.full(1000, 0.707 + 0.707j, dtype=numpy.complex64) + number_of_samples = len(waveform_data) + + waveform_data_ctypes = (NIComplexNumberF32 * number_of_samples)( + *[NIComplexNumberF32(real=0.707, imag=0.707) for _ in range(number_of_samples)] + ) + waveform_data_pointer = ctypes.cast(waveform_data_ctypes, ctypes.POINTER(NIComplexNumberF32)) + self.patched_library.niFake_WriteWaveformNumpyComplex64.side_effect = self.side_effects_helper.niFake_WriteWaveformNumpyComplex64 + interpreter = self.get_initialized_library_interpreter() + interpreter.write_waveform_numpy_complex64(waveform_data) + self.patched_library.niFake_WriteWaveformNumpyComplex64.assert_called_once_with( + _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), + _matchers.ViInt32Matcher(number_of_samples), + _matchers.NIComplexNumberF32PointerMatcher(waveform_data_pointer, number_of_samples) + ) + + def test_write_waveform_numpy_complex_interleaved_i16_valid_input(self): + from nifake._complextype import NIComplexI16 + + waveform_data = numpy.array([32767, 0] * 1000, dtype=numpy.int16) + number_of_samples = len(waveform_data) // 2 + waveform_data_ctypes = (NIComplexI16 * number_of_samples)( + *[NIComplexI16(real=32767, imag=0) for _ in range(number_of_samples)] + ) + waveform_data_pointer = ctypes.cast(waveform_data_ctypes, ctypes.POINTER(NIComplexI16)) + self.patched_library.niFake_WriteWaveformNumpyComplexInterleavedI16.side_effect = self.side_effects_helper.niFake_WriteWaveformNumpyComplexInterleavedI16 + interpreter = self.get_initialized_library_interpreter() + interpreter.write_waveform_numpy_complex_interleaved_i16(waveform_data) + self.patched_library.niFake_WriteWaveformNumpyComplexInterleavedI16.assert_called_once_with( + _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST), + _matchers.ViInt32Matcher(number_of_samples), + _matchers.NIComplexI16PointerMatcher(waveform_data_pointer, number_of_samples) + ) + def test_matcher_prints(self): assert _matchers.ViSessionMatcher(SESSION_NUM_FOR_TEST).__repr__() == "ViSessionMatcher(" + str(nifake._visatype.ViSession) + ", 42)" assert _matchers.ViAttrMatcher(SESSION_NUM_FOR_TEST).__repr__() == "ViAttrMatcher(" + str(nifake._visatype.ViAttr) + ", 42)" diff --git a/src/nifake/unit_tests/test_session.py b/src/nifake/unit_tests/test_session.py index 7f243dcf8..16af4e81a 100644 --- a/src/nifake/unit_tests/test_session.py +++ b/src/nifake/unit_tests/test_session.py @@ -837,6 +837,33 @@ def test_return_timedeltas(self): assert returned_timedeltas == expected_timedeltas self.patched_library_interpreter.return_list_of_durations_in_seconds.assert_called_once_with(len(time_values)) + def test_session_write_waveform_numpy_complex64_invalid_dtype(self): + invalid_waveform_data = numpy.full(10, 1.0 + 1.0j, dtype=numpy.complex128) + expected_error_message = "waveform_data_array must be numpy.ndarray of dtype=complex64, is complex128" + import pytest + with nifake.Session('dev1') as session: + with pytest.raises(TypeError) as exc_info: + session.write_waveform_numpy_complex64(invalid_waveform_data) + assert str(exc_info.value) == expected_error_message + + def test_session_write_waveform_numpy_complex128_invalid_dtype(self): + invalid_waveform_data = numpy.full(10, 1.0 + 1.0j, dtype=numpy.complex64) + expected_error_message = "waveform_data_array must be numpy.ndarray of dtype=complex128, is complex64" + import pytest + with nifake.Session('dev1') as session: + with pytest.raises(TypeError) as exc_info: + session.write_waveform_numpy_complex128(invalid_waveform_data) + assert str(exc_info.value) == expected_error_message + + def test_session_write_waveform_numpy_complex_interleaved_i16_invalid_dtype(self): + invalid_waveform_data = numpy.full(10, 1.0 + 1.0j, dtype=numpy.complex64) + expected_error_message = "waveform_data_array must be numpy.ndarray of dtype=int16, is complex64" + import pytest + with nifake.Session('dev1') as session: + with pytest.raises(TypeError) as exc_info: + session.write_waveform_numpy_complex_interleaved_i16(invalid_waveform_data) + assert str(exc_info.value) == expected_error_message + class TestGrpcSession: