diff --git a/build/helper/__init__.py b/build/helper/__init__.py index f6d8dbcfa..9d278dfe9 100644 --- a/build/helper/__init__.py +++ b/build/helper/__init__.py @@ -23,6 +23,9 @@ from build.helper.documentation_helper import get_function_docstring # noqa: F401 from build.helper.documentation_helper import get_function_rst # noqa: F401 from build.helper.documentation_helper import get_indented_docstring_snippet # noqa: F401 +from build.helper.documentation_helper import get_repeated_capability_element_recommendation # noqa: F401 +from build.helper.documentation_helper import get_repeated_capability_single_index_python_example # noqa: F401 +from build.helper.documentation_helper import get_repeated_capability_tuple_index_python_example # noqa: F401 from build.helper.documentation_helper import get_rst_header_snippet # noqa: F401 from build.helper.documentation_helper import get_rst_picture_reference # noqa: F401 from build.helper.documentation_helper import module_supports_repeated_caps # noqa: F401 diff --git a/build/helper/documentation_helper.py b/build/helper/documentation_helper.py index 1aade68d0..4f6933f40 100644 --- a/build/helper/documentation_helper.py +++ b/build/helper/documentation_helper.py @@ -56,6 +56,122 @@ def get_indented_docstring_snippet(d, indent=4): return ret_val +def get_repeated_capability_element_recommendation(rep_cap_config): + '''Returns a string recommending a specific type be useed for the repeated capability.''' + rep_cap_prefix = rep_cap_config['prefix'] + rep_cap_name = rep_cap_config['python_name'] + if rep_cap_prefix or rep_cap_name == 'channels': + element_type = 'an integer' + else: + element_type = 'a string' + + return f'The basic element for indexing this repeated capability is {element_type}.' + + +def _get_repeated_capability_example_info(rep_cap_config): + '''Returns values needed for building a rep cap doc snippet and explanation.''' + index = 0 + indices = ["0", "2"] # use strings so that we can call join + value_type = None # we only set this for enum values + + attr_for_example = rep_cap_config['attr_for_docs_example'] + attr_type_for_example = rep_cap_config['attr_type_for_docs_example'] + if attr_type_for_example == 'property': + class_attr_ref = f':py:attr:`{attr_for_example}`' + elif attr_type_for_example == 'method': + class_attr_ref = f':py:meth:`{attr_for_example}`' + + if 'indices_for_docs_example' in rep_cap_config: + index = rep_cap_config["indices_for_docs_example"][0] + if isinstance(index, str): + index = repr(index) + indices = [repr(index) for index in rep_cap_config["indices_for_docs_example"]] + + value = rep_cap_config['value_for_docs_example'] + value_type = type(value) + if 'value_type_for_docs_example' in rep_cap_config: + value_type = rep_cap_config['value_type_for_docs_example'] + if not value_type == 'enum' and isinstance(value, str): + value = repr(value) + + explanation_value = f':python:`{value}`' + if value_type == 'enum': + explanation_value = f':py:data:`~{value}`' + + ret_val = { + 'attr_for_example': attr_for_example, + 'attr_type_for_example': attr_type_for_example, + 'class_attr_ref': class_attr_ref, + 'explanation_value': explanation_value, + 'index': index, + 'indices': indices, + 'value': value, + } + return ret_val + + +def get_repeated_capability_single_index_python_example(rep_cap_config): + '''Returns a python code snippet and explanation for example usage of a repeated capability.''' + rep_cap_name = rep_cap_config['python_name'] + + rep_cap_info = _get_repeated_capability_example_info(rep_cap_config) + attr_for_example = rep_cap_info['attr_for_example'] + attr_type_for_example = rep_cap_info['attr_type_for_example'] + class_attr_ref = rep_cap_info['class_attr_ref'] + explanation_value = rep_cap_info['explanation_value'] + index = rep_cap_info['index'] + value = rep_cap_info['value'] + + if attr_type_for_example == "property": + if value is None: + snippet = f'print(session.{rep_cap_name}[{index}].{attr_for_example})' + explanation = f"prints {class_attr_ref} for {rep_cap_name} {index}." + else: + snippet = f'session.{rep_cap_name}[{index}].{attr_for_example} = {value}' + explanation = f"sets {class_attr_ref} to {explanation_value} for {rep_cap_name} {index}." + elif attr_type_for_example == "method": + if value is None: + snippet = f'session.{rep_cap_name}[{index}].{attr_for_example}()' + explanation = f"calls {class_attr_ref} for {rep_cap_name} {index}." + else: + snippet = f'session.{rep_cap_name}[{index}].{attr_for_example}({value})' + explanation = f"calls {class_attr_ref} with {explanation_value} for {rep_cap_name} {index}." + else: + raise ValueError(f"Ilegal value {attr_type_for_example} in {repr(rep_cap_config)}.") + return snippet, explanation + + +def get_repeated_capability_tuple_index_python_example(rep_cap_config): + '''Returns a python code snippet and explanation for example usage of a repeated capability.''' + rep_cap_name = rep_cap_config['python_name'] + + rep_cap_info = _get_repeated_capability_example_info(rep_cap_config) + attr_for_example = rep_cap_info['attr_for_example'] + attr_type_for_example = rep_cap_info['attr_type_for_example'] + class_attr_ref = rep_cap_info['class_attr_ref'] + explanation_value = rep_cap_info['explanation_value'] + indices = rep_cap_info['indices'] + value = rep_cap_info['value'] + + if attr_type_for_example == "property": + if value is None: + snippet = f'print(session.{rep_cap_name}[{", ".join(indices)}].{attr_for_example})' + explanation = f"prints {class_attr_ref} for {rep_cap_name} {', '.join(indices)}." + else: + snippet = f'session.{rep_cap_name}[{", ".join(indices)}].{attr_for_example} = {value}' + explanation = f"sets {class_attr_ref} to {explanation_value} for {rep_cap_name} {', '.join(indices)}." + elif attr_type_for_example == "method": + if value is None: + snippet = f'session.{rep_cap_name}[{", ".join(indices)}].{attr_for_example}()' + explanation = f"calls {class_attr_ref} for {rep_cap_name} {', '.join(indices)}." + else: + snippet = f'session.{rep_cap_name}[{", ".join(indices)}].{attr_for_example}({value})' + explanation = f"calls {class_attr_ref} with {explanation_value} for {rep_cap_name} {', '.join(indices)}." + else: + raise ValueError(f"Ilegal value {attr_type_for_example} in {repr(rep_cap_config)}.") + return snippet, explanation + + def get_rst_header_snippet(t, header_level='='): '''Get rst formatted heading''' ret_val = t + '\n' diff --git a/build/templates/rep_caps.rst.mako b/build/templates/rep_caps.rst.mako index 179d56e1f..64fbf46de 100644 --- a/build/templates/rep_caps.rst.mako +++ b/build/templates/rep_caps.rst.mako @@ -19,48 +19,48 @@ ${helper.get_rst_header_snippet('Repeated Capabilities', '=')} - Repeated capabilities attributes are used to set the `channel_string` parameter to the - underlying driver function call. This can be the actual function based on the :py:class:`Session` - method being called, or it can be the appropriate Get/Set Attribute function, such as :c:`${config['c_function_prefix']}SetAttributeViInt32()`. + :py:class:`${module_name}.Session` supports "Repeated Capabilities", which are multiple instances of the same type of + functionality. The repeated capabilities supported by :py:class:`${module_name}.Session` are: - Repeated capabilities attributes use the indexing operator :python:`[]` to indicate the repeated capabilities. - The parameter can be a string, list, tuple, or slice (range). Each element of those can be a string or - an integer. If it is a string, you can indicate a range using the same format as the driver: :python:`'0-2'` or - :python:`'0:2'` +% for rep_cap in config['repeated_capabilities']: +<% +name = rep_cap['python_name'] +%>\ + #. ${name}_ +% endfor + + Use the indexing operator :python:`[]` to indicate which repeated capability instance you are trying to access. + The parameter can be a single element or an iterable that implements sequence semantics, such as list, tuple, range and slice. - Some repeated capabilities use a prefix before the number and this is optional + A single element will access one repeated capability. + + An iterable will access multiple repeated capabilites at once. % for rep_cap in config['repeated_capabilities']: <% name = rep_cap['python_name'] -prefix = rep_cap['prefix'] + +single_index_snippet, single_index_explanation = helper.get_repeated_capability_single_index_python_example(rep_cap) +tuple_index_snippet, tuple_index_explanation = helper.get_repeated_capability_tuple_index_python_example(rep_cap) + %>\ ${helper.get_rst_header_snippet(name, '-')} .. py:attribute:: ${module_name}.Session.${name}[] -% if len(prefix) > 0: - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + ${helper.get_repeated_capability_element_recommendation(rep_cap)} .. code:: python - session.${name}['0-2'].channel_enabled = True + ${single_index_snippet} - passes a string of :python:`'${prefix}0, ${prefix}1, ${prefix}2'` to the set attribute function. + ${single_index_explanation} - If an invalid repeated capability is passed to the driver, the driver will return an error. - - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. - -% endif .. code:: python - session.${name}['${prefix}0-${prefix}2'].channel_enabled = True - - passes a string of :python:`'${prefix}0, ${prefix}1, ${prefix}2'` to the set attribute function. + ${tuple_index_snippet} + ${tuple_index_explanation} % endfor diff --git a/build/unit_tests/test_documentation_helper.py b/build/unit_tests/test_documentation_helper.py index f87abb97e..75d900600 100644 --- a/build/unit_tests/test_documentation_helper.py +++ b/build/unit_tests/test_documentation_helper.py @@ -1,3 +1,5 @@ +import pytest + from build.helper.documentation_helper import * @@ -727,3 +729,230 @@ def test_add_notes_re_links(): assert attr_note_text in local_config['functions']['MakeAFoo']['parameters'][1]['documentation']['note'] assert enum_note_text in local_config['functions']['MakeAFoo']['parameters'][1]['documentation']['note'] + +@pytest.mark.parametrize( + "rep_cap,recommendation", + [ + pytest.param( + { + 'prefix': '', + 'python_name': 'channels', + }, + 'The basic element for indexing this repeated capability is an integer.', + id="no_prefix-channels", + ), + pytest.param( + { + 'prefix': '', + 'python_name': 'non-channels_cap', + }, + 'The basic element for indexing this repeated capability is a string.', + id="no_prefix-other", + ), + pytest.param( + { + 'prefix': 'RepCap', + 'python_name': 'any_rep_cap', + }, + 'The basic element for indexing this repeated capability is an integer.', + id="prefix", + ), + ], +) +def test_get_repeated_capability_element_recommendation(rep_cap, recommendation): + assert recommendation == get_repeated_capability_element_recommendation(rep_cap) + + +@pytest.mark.parametrize( + "rep_cap,snippet,explanation", + [ + pytest.param( + { + 'attr_for_docs_example': 'channel_enabled', + 'attr_type_for_docs_example': 'property', + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': True, + }, + 'session.channels[0].channel_enabled = True', + 'sets :py:attr:`channel_enabled` to :python:`True` for channels 0.', + id="defaults", + ), + pytest.param( + { + 'attr_for_docs_example': 'exported_pattern_opcode_event_output_terminal', + 'attr_type_for_docs_example': 'property', + 'prefix': 'patternOpcodeEvent', + 'python_name': 'pattern_opcode_events', + 'value_for_docs_example': '/Dev1/PXI_Trig0', + }, + "session.pattern_opcode_events[0].exported_pattern_opcode_event_output_terminal = '/Dev1/PXI_Trig0'", + "sets :py:attr:`exported_pattern_opcode_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for pattern_opcode_events 0.", + id="property_with_string_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'channel_enabled', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': [0, 1], + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': True, + }, + 'session.channels[0].channel_enabled = True', + 'sets :py:attr:`channel_enabled` to :python:`True` for channels 0.', + id="custom_indices", + ), + pytest.param( + { + 'attr_for_docs_example': 'vil', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["PinA", "PinB", "CPin"], + 'prefix': '', + 'python_name': 'pins', + 'value_for_docs_example': 2, + }, + "session.pins['PinA'].vil = 2", + "sets :py:attr:`vil` to :python:`2` for pins 'PinA'.", + id="string_indices_with_numerical_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'disable_sites', + 'attr_type_for_docs_example': 'method', + 'prefix': 'site', + 'python_name': 'sites', + 'value_for_docs_example': None, + }, + "session.sites[0].disable_sites()", + "calls :py:meth:`disable_sites` for sites 0.", + id="method_no_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'serial_number', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["Dev1", "Dev2", "3rdDevice"], + 'prefix': '', + 'python_name': 'instruments', + 'value_for_docs_example': None, + }, + "print(session.instruments['Dev1'].serial_number)", + "prints :py:attr:`serial_number` for instruments 'Dev1'.", + id="property_no_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'conditional_jump_trigger_type', + 'attr_type_for_docs_example': 'property', + 'prefix': 'conditionalJumpTrigger', + 'python_name': 'conditional_jump_triggers', + 'value_for_docs_example': 'nidigital.TriggerType.DIGITAL_EDGE', + 'value_type_for_docs_example': 'enum', + }, + "session.conditional_jump_triggers[0].conditional_jump_trigger_type = nidigital.TriggerType.DIGITAL_EDGE", + "sets :py:attr:`conditional_jump_trigger_type` to :py:data:`~nidigital.TriggerType.DIGITAL_EDGE` for conditional_jump_triggers 0.", + id="enum_val", + ), + ], +) +def test_get_repeated_capability_single_index_python_example(rep_cap, snippet, explanation): + assert (snippet, explanation) == get_repeated_capability_single_index_python_example(rep_cap) + + +@pytest.mark.parametrize( + "rep_cap,snippet,explanation", + [ + pytest.param( + { + 'attr_for_docs_example': 'channel_enabled', + 'attr_type_for_docs_example': 'property', + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': True, + }, + 'session.channels[0, 2].channel_enabled = True', + 'sets :py:attr:`channel_enabled` to :python:`True` for channels 0, 2.', + id="defaults", + ), + pytest.param( + { + 'attr_for_docs_example': 'exported_pattern_opcode_event_output_terminal', + 'attr_type_for_docs_example': 'property', + 'prefix': 'patternOpcodeEvent', + 'python_name': 'pattern_opcode_events', + 'value_for_docs_example': '/Dev1/PXI_Trig0', + }, + "session.pattern_opcode_events[0, 2].exported_pattern_opcode_event_output_terminal = '/Dev1/PXI_Trig0'", + "sets :py:attr:`exported_pattern_opcode_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for pattern_opcode_events 0, 2.", + id="property_with_string_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'channel_enabled', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': [0, 1], + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': True, + }, + 'session.channels[0, 1].channel_enabled = True', + 'sets :py:attr:`channel_enabled` to :python:`True` for channels 0, 1.', + id="custom_indices", + ), + pytest.param( + { + 'attr_for_docs_example': 'vil', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["PinA", "PinB", "CPin"], + 'prefix': '', + 'python_name': 'pins', + 'value_for_docs_example': 2, + }, + "session.pins['PinA', 'PinB', 'CPin'].vil = 2", + "sets :py:attr:`vil` to :python:`2` for pins 'PinA', 'PinB', 'CPin'.", + id="string_indices_with_numerical_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'disable_sites', + 'attr_type_for_docs_example': 'method', + 'prefix': 'site', + 'python_name': 'sites', + 'value_for_docs_example': None, + }, + "session.sites[0, 2].disable_sites()", + "calls :py:meth:`disable_sites` for sites 0, 2.", + id="method_no_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'serial_number', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["Dev1", "Dev2", "3rdDevice"], + 'prefix': '', + 'python_name': 'instruments', + 'value_for_docs_example': None, + }, + "print(session.instruments['Dev1', 'Dev2', '3rdDevice'].serial_number)", + "prints :py:attr:`serial_number` for instruments 'Dev1', 'Dev2', '3rdDevice'.", + id="property_no_val", + ), + pytest.param( + { + 'attr_for_docs_example': 'conditional_jump_trigger_type', + 'attr_type_for_docs_example': 'property', + 'prefix': 'conditionalJumpTrigger', + 'python_name': 'conditional_jump_triggers', + 'value_for_docs_example': 'nidigital.TriggerType.DIGITAL_EDGE', + 'value_type_for_docs_example': 'enum', + }, + "session.conditional_jump_triggers[0, 2].conditional_jump_trigger_type = nidigital.TriggerType.DIGITAL_EDGE", + "sets :py:attr:`conditional_jump_trigger_type` to :py:data:`~nidigital.TriggerType.DIGITAL_EDGE` for conditional_jump_triggers 0, 2.", + id="enum_val", + ), + ], +) +def test_get_repeated_capability_tuple_index_python_example(rep_cap, snippet, explanation): + assert (snippet, explanation) == get_repeated_capability_tuple_index_python_example(rep_cap) + diff --git a/docs/nidcpower/rep_caps.rst b/docs/nidcpower/rep_caps.rst index 6078e4dea..f7b13dc52 100644 --- a/docs/nidcpower/rep_caps.rst +++ b/docs/nidcpower/rep_caps.rst @@ -12,39 +12,55 @@ Repeated Capabilities ===================== - Repeated capabilities attributes are used to set the `channel_string` parameter to the - underlying driver function call. This can be the actual function based on the :py:class:`Session` - method being called, or it can be the appropriate Get/Set Attribute function, such as :c:`niDCPower_SetAttributeViInt32()`. + :py:class:`nidcpower.Session` supports "Repeated Capabilities", which are multiple instances of the same type of + functionality. The repeated capabilities supported by :py:class:`nidcpower.Session` are: - Repeated capabilities attributes use the indexing operator :python:`[]` to indicate the repeated capabilities. - The parameter can be a string, list, tuple, or slice (range). Each element of those can be a string or - an integer. If it is a string, you can indicate a range using the same format as the driver: :python:`'0-2'` or - :python:`'0:2'` + #. channels_ + #. instruments_ - Some repeated capabilities use a prefix before the number and this is optional + Use the indexing operator :python:`[]` to indicate which repeated capability instance you are trying to access. + The parameter can be a single element or an iterable that implements sequence semantics, such as list, tuple, range and slice. + + A single element will access one repeated capability. + + An iterable will access multiple repeated capabilites at once. channels -------- .. py:attribute:: nidcpower.Session.channels[] + The basic element for indexing this repeated capability is an integer. + .. code:: python - session.channels['0-2'].channel_enabled = True + session.channels[0].output_function = nidcpower.OutputFunction.DC_CURRENT + + sets :py:attr:`output_function` to :py:data:`~nidcpower.OutputFunction.DC_CURRENT` for channels 0. + + .. code:: python - passes a string of :python:`'0, 1, 2'` to the set attribute function. + session.channels[0, 2].output_function = nidcpower.OutputFunction.DC_CURRENT + sets :py:attr:`output_function` to :py:data:`~nidcpower.OutputFunction.DC_CURRENT` for channels 0, 2. instruments ----------- .. py:attribute:: nidcpower.Session.instruments[] + The basic element for indexing this repeated capability is a string. + .. code:: python - session.instruments['0-2'].channel_enabled = True + print(session.instruments['Dev1'].serial_number) + + prints :py:attr:`serial_number` for instruments 'Dev1'. + + .. code:: python - passes a string of :python:`'0, 1, 2'` to the set attribute function. + print(session.instruments['Dev1', 'Dev2', '3rdDevice'].serial_number) + prints :py:attr:`serial_number` for instruments 'Dev1', 'Dev2', '3rdDevice'. diff --git a/docs/nidigital/rep_caps.rst b/docs/nidigital/rep_caps.rst index 32550fc4f..2820ce2b3 100644 --- a/docs/nidigital/rep_caps.rst +++ b/docs/nidigital/rep_caps.rst @@ -12,181 +12,175 @@ Repeated Capabilities ===================== - Repeated capabilities attributes are used to set the `channel_string` parameter to the - underlying driver function call. This can be the actual function based on the :py:class:`Session` - method being called, or it can be the appropriate Get/Set Attribute function, such as :c:`niDigital_SetAttributeViInt32()`. + :py:class:`nidigital.Session` supports "Repeated Capabilities", which are multiple instances of the same type of + functionality. The repeated capabilities supported by :py:class:`nidigital.Session` are: - Repeated capabilities attributes use the indexing operator :python:`[]` to indicate the repeated capabilities. - The parameter can be a string, list, tuple, or slice (range). Each element of those can be a string or - an integer. If it is a string, you can indicate a range using the same format as the driver: :python:`'0-2'` or - :python:`'0:2'` + #. channels_ + #. pins_ + #. instruments_ + #. pattern_opcode_events_ + #. conditional_jump_triggers_ + #. sites_ + #. rio_events_ + #. rio_triggers_ - Some repeated capabilities use a prefix before the number and this is optional + Use the indexing operator :python:`[]` to indicate which repeated capability instance you are trying to access. + The parameter can be a single element or an iterable that implements sequence semantics, such as list, tuple, range and slice. + + A single element will access one repeated capability. + + An iterable will access multiple repeated capabilites at once. channels -------- .. py:attribute:: nidigital.Session.channels[] + The basic element for indexing this repeated capability is an integer. + .. code:: python - session.channels['0-2'].channel_enabled = True + session.channels[0].vil = 2 + + sets :py:attr:`vil` to :python:`2` for channels 0. - passes a string of :python:`'0, 1, 2'` to the set attribute function. + .. code:: python + + session.channels[0, 2].vil = 2 + sets :py:attr:`vil` to :python:`2` for channels 0, 2. pins ---- .. py:attribute:: nidigital.Session.pins[] + The basic element for indexing this repeated capability is a string. + .. code:: python - session.pins['0-2'].channel_enabled = True + session.pins['PinA'].vil = 2 - passes a string of :python:`'0, 1, 2'` to the set attribute function. + sets :py:attr:`vil` to :python:`2` for pins 'PinA'. + .. code:: python + + session.pins['PinA', 'PinB', 'CPin'].vil = 2 + + sets :py:attr:`vil` to :python:`2` for pins 'PinA', 'PinB', 'CPin'. instruments ----------- .. py:attribute:: nidigital.Session.instruments[] + The basic element for indexing this repeated capability is a string. + .. code:: python - session.instruments['0-2'].channel_enabled = True + session.instruments['Dev1'].timing_absolute_delay = 5e-09 - passes a string of :python:`'0, 1, 2'` to the set attribute function. + sets :py:attr:`timing_absolute_delay` to :python:`5e-09` for instruments 'Dev1'. + .. code:: python + + session.instruments['Dev1', 'Dev2', '3rdDevice'].timing_absolute_delay = 5e-09 + + sets :py:attr:`timing_absolute_delay` to :python:`5e-09` for instruments 'Dev1', 'Dev2', '3rdDevice'. pattern_opcode_events --------------------- .. py:attribute:: nidigital.Session.pattern_opcode_events[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.pattern_opcode_events['0-2'].channel_enabled = True - - passes a string of :python:`'patternOpcodeEvent0, patternOpcodeEvent1, patternOpcodeEvent2'` to the set attribute function. + session.pattern_opcode_events[0].exported_pattern_opcode_event_output_terminal = '/Dev1/PXI_Trig0' - If an invalid repeated capability is passed to the driver, the driver will return an error. - - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + sets :py:attr:`exported_pattern_opcode_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for pattern_opcode_events 0. .. code:: python - session.pattern_opcode_events['patternOpcodeEvent0-patternOpcodeEvent2'].channel_enabled = True - - passes a string of :python:`'patternOpcodeEvent0, patternOpcodeEvent1, patternOpcodeEvent2'` to the set attribute function. + session.pattern_opcode_events[0, 2].exported_pattern_opcode_event_output_terminal = '/Dev1/PXI_Trig0' + sets :py:attr:`exported_pattern_opcode_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for pattern_opcode_events 0, 2. conditional_jump_triggers ------------------------- .. py:attribute:: nidigital.Session.conditional_jump_triggers[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.conditional_jump_triggers['0-2'].channel_enabled = True - - passes a string of :python:`'conditionalJumpTrigger0, conditionalJumpTrigger1, conditionalJumpTrigger2'` to the set attribute function. - - If an invalid repeated capability is passed to the driver, the driver will return an error. + session.conditional_jump_triggers[0].conditional_jump_trigger_type = nidigital.TriggerType.DIGITAL_EDGE - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + sets :py:attr:`conditional_jump_trigger_type` to :py:data:`~nidigital.TriggerType.DIGITAL_EDGE` for conditional_jump_triggers 0. .. code:: python - session.conditional_jump_triggers['conditionalJumpTrigger0-conditionalJumpTrigger2'].channel_enabled = True - - passes a string of :python:`'conditionalJumpTrigger0, conditionalJumpTrigger1, conditionalJumpTrigger2'` to the set attribute function. + session.conditional_jump_triggers[0, 2].conditional_jump_trigger_type = nidigital.TriggerType.DIGITAL_EDGE + sets :py:attr:`conditional_jump_trigger_type` to :py:data:`~nidigital.TriggerType.DIGITAL_EDGE` for conditional_jump_triggers 0, 2. sites ----- .. py:attribute:: nidigital.Session.sites[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.sites['0-2'].channel_enabled = True - - passes a string of :python:`'site0, site1, site2'` to the set attribute function. - - If an invalid repeated capability is passed to the driver, the driver will return an error. + session.sites[0].disable_sites() - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + calls :py:meth:`disable_sites` for sites 0. .. code:: python - session.sites['site0-site2'].channel_enabled = True - - passes a string of :python:`'site0, site1, site2'` to the set attribute function. + session.sites[0, 2].disable_sites() + calls :py:meth:`disable_sites` for sites 0, 2. rio_events ---------- .. py:attribute:: nidigital.Session.rio_events[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.rio_events['0-2'].channel_enabled = True - - passes a string of :python:`'RIOEvent0, RIOEvent1, RIOEvent2'` to the set attribute function. + session.rio_events[0].exported_rio_event_output_terminal = '/Dev1/PXI_Trig0' - If an invalid repeated capability is passed to the driver, the driver will return an error. - - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + sets :py:attr:`exported_rio_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for rio_events 0. .. code:: python - session.rio_events['RIOEvent0-RIOEvent2'].channel_enabled = True - - passes a string of :python:`'RIOEvent0, RIOEvent1, RIOEvent2'` to the set attribute function. + session.rio_events[0, 2].exported_rio_event_output_terminal = '/Dev1/PXI_Trig0' + sets :py:attr:`exported_rio_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for rio_events 0, 2. rio_triggers ------------ .. py:attribute:: nidigital.Session.rio_triggers[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.rio_triggers['0-2'].channel_enabled = True + session.rio_triggers[0].rio_trigger_type = nidigital.TriggerType.DIGITAL_EDGE - passes a string of :python:`'RIOTrigger0, RIOTrigger1, RIOTrigger2'` to the set attribute function. - - If an invalid repeated capability is passed to the driver, the driver will return an error. - - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + sets :py:attr:`rio_trigger_type` to :py:data:`~nidigital.TriggerType.DIGITAL_EDGE` for rio_triggers 0. .. code:: python - session.rio_triggers['RIOTrigger0-RIOTrigger2'].channel_enabled = True - - passes a string of :python:`'RIOTrigger0, RIOTrigger1, RIOTrigger2'` to the set attribute function. + session.rio_triggers[0, 2].rio_trigger_type = nidigital.TriggerType.DIGITAL_EDGE + sets :py:attr:`rio_trigger_type` to :py:data:`~nidigital.TriggerType.DIGITAL_EDGE` for rio_triggers 0, 2. diff --git a/docs/nifgen/rep_caps.rst b/docs/nifgen/rep_caps.rst index 5890a432e..143aa716b 100644 --- a/docs/nifgen/rep_caps.rst +++ b/docs/nifgen/rep_caps.rst @@ -12,105 +12,95 @@ Repeated Capabilities ===================== - Repeated capabilities attributes are used to set the `channel_string` parameter to the - underlying driver function call. This can be the actual function based on the :py:class:`Session` - method being called, or it can be the appropriate Get/Set Attribute function, such as :c:`niFgen_SetAttributeViInt32()`. + :py:class:`nifgen.Session` supports "Repeated Capabilities", which are multiple instances of the same type of + functionality. The repeated capabilities supported by :py:class:`nifgen.Session` are: - Repeated capabilities attributes use the indexing operator :python:`[]` to indicate the repeated capabilities. - The parameter can be a string, list, tuple, or slice (range). Each element of those can be a string or - an integer. If it is a string, you can indicate a range using the same format as the driver: :python:`'0-2'` or - :python:`'0:2'` + #. channels_ + #. script_triggers_ + #. markers_ + #. data_markers_ - Some repeated capabilities use a prefix before the number and this is optional + Use the indexing operator :python:`[]` to indicate which repeated capability instance you are trying to access. + The parameter can be a single element or an iterable that implements sequence semantics, such as list, tuple, range and slice. + + A single element will access one repeated capability. + + An iterable will access multiple repeated capabilites at once. channels -------- .. py:attribute:: nifgen.Session.channels[] + The basic element for indexing this repeated capability is an integer. + .. code:: python - session.channels['0-2'].channel_enabled = True + session.channels[0].func_amplitude = 0.5 + + sets :py:attr:`func_amplitude` to :python:`0.5` for channels 0. - passes a string of :python:`'0, 1, 2'` to the set attribute function. + .. code:: python + + session.channels[0, 1].func_amplitude = 0.5 + sets :py:attr:`func_amplitude` to :python:`0.5` for channels 0, 1. script_triggers --------------- .. py:attribute:: nifgen.Session.script_triggers[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.script_triggers['0-2'].channel_enabled = True - - passes a string of :python:`'ScriptTrigger0, ScriptTrigger1, ScriptTrigger2'` to the set attribute function. - - If an invalid repeated capability is passed to the driver, the driver will return an error. + session.script_triggers[0].exported_script_trigger_output_terminal = '/Dev1/PXI_Trig0' - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + sets :py:attr:`exported_script_trigger_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for script_triggers 0. .. code:: python - session.script_triggers['ScriptTrigger0-ScriptTrigger2'].channel_enabled = True - - passes a string of :python:`'ScriptTrigger0, ScriptTrigger1, ScriptTrigger2'` to the set attribute function. + session.script_triggers[0, 2].exported_script_trigger_output_terminal = '/Dev1/PXI_Trig0' + sets :py:attr:`exported_script_trigger_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for script_triggers 0, 2. markers ------- .. py:attribute:: nifgen.Session.markers[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.markers['0-2'].channel_enabled = True - - passes a string of :python:`'Marker0, Marker1, Marker2'` to the set attribute function. + session.markers[0].marker_event_output_terminal = '/Dev1/PXI_Trig0' - If an invalid repeated capability is passed to the driver, the driver will return an error. - - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + sets :py:attr:`marker_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for markers 0. .. code:: python - session.markers['Marker0-Marker2'].channel_enabled = True - - passes a string of :python:`'Marker0, Marker1, Marker2'` to the set attribute function. + session.markers[0, 2].marker_event_output_terminal = '/Dev1/PXI_Trig0' + sets :py:attr:`marker_event_output_terminal` to :python:`'/Dev1/PXI_Trig0'` for markers 0, 2. data_markers ------------ .. py:attribute:: nifgen.Session.data_markers[] - If no prefix is added to the items in the parameter, the correct prefix will be added when - the driver function call is made. + The basic element for indexing this repeated capability is an integer. .. code:: python - session.data_markers['0-2'].channel_enabled = True + session.data_markers[0].data_marker_event_level_polarity = nifgen.DataMarkerEventLevelPolarity.LOW - passes a string of :python:`'DataMarker0, DataMarker1, DataMarker2'` to the set attribute function. - - If an invalid repeated capability is passed to the driver, the driver will return an error. - - You can also explicitly use the prefix as part of the parameter, but it must be the correct prefix - for the specific repeated capability. + sets :py:attr:`data_marker_event_level_polarity` to :py:data:`~nifgen.DataMarkerEventLevelPolarity.LOW` for data_markers 0. .. code:: python - session.data_markers['DataMarker0-DataMarker2'].channel_enabled = True - - passes a string of :python:`'DataMarker0, DataMarker1, DataMarker2'` to the set attribute function. + session.data_markers[0, 2].data_marker_event_level_polarity = nifgen.DataMarkerEventLevelPolarity.LOW + sets :py:attr:`data_marker_event_level_polarity` to :py:data:`~nifgen.DataMarkerEventLevelPolarity.LOW` for data_markers 0, 2. diff --git a/docs/niscope/rep_caps.rst b/docs/niscope/rep_caps.rst index 19169bc08..0d39d82f3 100644 --- a/docs/niscope/rep_caps.rst +++ b/docs/niscope/rep_caps.rst @@ -12,39 +12,55 @@ Repeated Capabilities ===================== - Repeated capabilities attributes are used to set the `channel_string` parameter to the - underlying driver function call. This can be the actual function based on the :py:class:`Session` - method being called, or it can be the appropriate Get/Set Attribute function, such as :c:`niScope_SetAttributeViInt32()`. + :py:class:`niscope.Session` supports "Repeated Capabilities", which are multiple instances of the same type of + functionality. The repeated capabilities supported by :py:class:`niscope.Session` are: - Repeated capabilities attributes use the indexing operator :python:`[]` to indicate the repeated capabilities. - The parameter can be a string, list, tuple, or slice (range). Each element of those can be a string or - an integer. If it is a string, you can indicate a range using the same format as the driver: :python:`'0-2'` or - :python:`'0:2'` + #. channels_ + #. instruments_ - Some repeated capabilities use a prefix before the number and this is optional + Use the indexing operator :python:`[]` to indicate which repeated capability instance you are trying to access. + The parameter can be a single element or an iterable that implements sequence semantics, such as list, tuple, range and slice. + + A single element will access one repeated capability. + + An iterable will access multiple repeated capabilites at once. channels -------- .. py:attribute:: niscope.Session.channels[] + The basic element for indexing this repeated capability is an integer. + .. code:: python - session.channels['0-2'].channel_enabled = True + session.channels[0].channel_enabled = True + + sets :py:attr:`channel_enabled` to :python:`True` for channels 0. + + .. code:: python - passes a string of :python:`'0, 1, 2'` to the set attribute function. + session.channels[0, 2].channel_enabled = True + sets :py:attr:`channel_enabled` to :python:`True` for channels 0, 2. instruments ----------- .. py:attribute:: niscope.Session.instruments[] + The basic element for indexing this repeated capability is a string. + .. code:: python - session.instruments['0-2'].channel_enabled = True + print(session.instruments['Dev1'].serial_number) + + prints :py:attr:`serial_number` for instruments 'Dev1'. + + .. code:: python - passes a string of :python:`'0, 1, 2'` to the set attribute function. + print(session.instruments['Dev1', 'Dev2', '3rdDevice'].serial_number) + prints :py:attr:`serial_number` for instruments 'Dev1', 'Dev2', '3rdDevice'. diff --git a/docs/niswitch/rep_caps.rst b/docs/niswitch/rep_caps.rst index 7f141fa26..0864239c9 100644 --- a/docs/niswitch/rep_caps.rst +++ b/docs/niswitch/rep_caps.rst @@ -12,27 +12,35 @@ Repeated Capabilities ===================== - Repeated capabilities attributes are used to set the `channel_string` parameter to the - underlying driver function call. This can be the actual function based on the :py:class:`Session` - method being called, or it can be the appropriate Get/Set Attribute function, such as :c:`niSwitch_SetAttributeViInt32()`. + :py:class:`niswitch.Session` supports "Repeated Capabilities", which are multiple instances of the same type of + functionality. The repeated capabilities supported by :py:class:`niswitch.Session` are: - Repeated capabilities attributes use the indexing operator :python:`[]` to indicate the repeated capabilities. - The parameter can be a string, list, tuple, or slice (range). Each element of those can be a string or - an integer. If it is a string, you can indicate a range using the same format as the driver: :python:`'0-2'` or - :python:`'0:2'` + #. channels_ - Some repeated capabilities use a prefix before the number and this is optional + Use the indexing operator :python:`[]` to indicate which repeated capability instance you are trying to access. + The parameter can be a single element or an iterable that implements sequence semantics, such as list, tuple, range and slice. + + A single element will access one repeated capability. + + An iterable will access multiple repeated capabilites at once. channels -------- .. py:attribute:: niswitch.Session.channels[] + The basic element for indexing this repeated capability is an integer. + .. code:: python - session.channels['0-2'].channel_enabled = True + session.channels[0].is_source_channel = True + + sets :py:attr:`is_source_channel` to :python:`True` for channels 0. + + .. code:: python - passes a string of :python:`'0, 1, 2'` to the set attribute function. + session.channels[0, 2].is_source_channel = True + sets :py:attr:`is_source_channel` to :python:`True` for channels 0, 2. diff --git a/src/nidcpower/metadata/config_addon.py b/src/nidcpower/metadata/config_addon.py index c8631d95a..048118a43 100644 --- a/src/nidcpower/metadata/config_addon.py +++ b/src/nidcpower/metadata/config_addon.py @@ -3,4 +3,22 @@ 'module_version': '1.4.6.dev0', 'latest_runtime_version_tested_against': '2023 Q2', 'initial_release_year': '2017', + 'repeated_capabilities': [ + { + 'attr_for_docs_example': 'output_function', + 'attr_type_for_docs_example': 'property', + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': 'nidcpower.OutputFunction.DC_CURRENT', + 'value_type_for_docs_example': 'enum', + }, + { + 'attr_for_docs_example': 'serial_number', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["Dev1", "Dev2", "3rdDevice"], + 'prefix': '', + 'python_name': 'instruments', + 'value_for_docs_example': None, + } + ], } diff --git a/src/nidigital/metadata/config_addon.py b/src/nidigital/metadata/config_addon.py index 53400d192..8b5969c0b 100644 --- a/src/nidigital/metadata/config_addon.py +++ b/src/nidigital/metadata/config_addon.py @@ -10,4 +10,66 @@ 'python_name': 'HistoryRAMCycleInformation' } ], + 'repeated_capabilities': [ + { + 'attr_for_docs_example': 'vil', + 'attr_type_for_docs_example': 'property', + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': 2, + }, + { + 'attr_for_docs_example': 'vil', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["PinA", "PinB", "CPin"], + 'prefix': '', + 'python_name': 'pins', + 'value_for_docs_example': 2, + }, + { + 'attr_for_docs_example': 'timing_absolute_delay', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["Dev1", "Dev2", "3rdDevice"], + 'prefix': '', + 'python_name': 'instruments', + 'value_for_docs_example': 5e-09, + }, + { + 'attr_for_docs_example': 'exported_pattern_opcode_event_output_terminal', + 'attr_type_for_docs_example': 'property', + 'prefix': 'patternOpcodeEvent', + 'python_name': 'pattern_opcode_events', + 'value_for_docs_example': '/Dev1/PXI_Trig0', + }, + { + 'attr_for_docs_example': 'conditional_jump_trigger_type', + 'attr_type_for_docs_example': 'property', + 'prefix': 'conditionalJumpTrigger', + 'python_name': 'conditional_jump_triggers', + 'value_for_docs_example': 'nidigital.TriggerType.DIGITAL_EDGE', + 'value_type_for_docs_example': 'enum', + }, + { + 'attr_for_docs_example': 'disable_sites', + 'attr_type_for_docs_example': 'method', + 'prefix': 'site', + 'python_name': 'sites', + 'value_for_docs_example': None, + }, + { + 'attr_for_docs_example': 'exported_rio_event_output_terminal', + 'attr_type_for_docs_example': 'property', + 'prefix': 'RIOEvent', + 'python_name': 'rio_events', + 'value_for_docs_example': '/Dev1/PXI_Trig0', + }, + { + 'attr_for_docs_example': 'rio_trigger_type', + 'attr_type_for_docs_example': 'property', + 'prefix': 'RIOTrigger', + 'python_name': 'rio_triggers', + 'value_for_docs_example': 'nidigital.TriggerType.DIGITAL_EDGE', + 'value_type_for_docs_example': 'enum', + } + ], } diff --git a/src/nifgen/metadata/config_addon.py b/src/nifgen/metadata/config_addon.py index 219a685a3..51285ea10 100644 --- a/src/nifgen/metadata/config_addon.py +++ b/src/nifgen/metadata/config_addon.py @@ -3,4 +3,36 @@ 'module_version': '1.4.6.dev0', 'latest_runtime_version_tested_against': '2023 Q1.1', 'initial_release_year': '2017', + 'repeated_capabilities': [ + { + 'attr_for_docs_example': 'func_amplitude', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': [0, 1], + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': 0.5, + }, + { + 'attr_for_docs_example': 'exported_script_trigger_output_terminal', + 'attr_type_for_docs_example': 'property', + 'prefix': 'ScriptTrigger', + 'python_name': 'script_triggers', + 'value_for_docs_example': '/Dev1/PXI_Trig0', + }, + { + 'attr_for_docs_example': 'marker_event_output_terminal', + 'attr_type_for_docs_example': 'property', + 'prefix': 'Marker', + 'python_name': 'markers', + 'value_for_docs_example': '/Dev1/PXI_Trig0', + }, + { + 'attr_for_docs_example': 'data_marker_event_level_polarity', + 'attr_type_for_docs_example': 'property', + 'prefix': 'DataMarker', + 'python_name': 'data_markers', + 'value_for_docs_example': 'nifgen.DataMarkerEventLevelPolarity.LOW', + 'value_type_for_docs_example': 'enum', + } + ], } diff --git a/src/niscope/metadata/config_addon.py b/src/niscope/metadata/config_addon.py index a8908b97e..5b901b5b6 100644 --- a/src/niscope/metadata/config_addon.py +++ b/src/niscope/metadata/config_addon.py @@ -15,5 +15,22 @@ 'file_name': 'measurement_stats', 'python_name': 'MeasurementStats' } - ] + ], + 'repeated_capabilities': [ + { + 'attr_for_docs_example': 'channel_enabled', + 'attr_type_for_docs_example': 'property', + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': True, + }, + { + 'attr_for_docs_example': 'serial_number', + 'attr_type_for_docs_example': 'property', + 'indices_for_docs_example': ["Dev1", "Dev2", "3rdDevice"], + 'prefix': '', + 'python_name': 'instruments', + 'value_for_docs_example': None, + } + ], } diff --git a/src/niswitch/metadata/config_addon.py b/src/niswitch/metadata/config_addon.py index 4c5df38f2..b0786b575 100644 --- a/src/niswitch/metadata/config_addon.py +++ b/src/niswitch/metadata/config_addon.py @@ -3,4 +3,13 @@ 'module_version': '1.4.6.dev0', 'latest_runtime_version_tested_against': '2023 Q1', 'initial_release_year': '2017', + 'repeated_capabilities': [ + { + 'attr_for_docs_example': 'is_source_channel', + 'attr_type_for_docs_example': 'property', + 'prefix': '', + 'python_name': 'channels', + 'value_for_docs_example': True, + } + ], }