Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repeated Capabilites documentation improvements #1686

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e9b6f72
Repeated Capabilites documentation improvements
ni-jfitzger Jan 21, 2022
7b3a1a5
codegen with rep_caps.rst changes
ni-jfitzger Jan 24, 2022
8bc69bc
Remove comment containing tips we decided weren't useful
ni-jfitzger Jan 28, 2022
93d62f1
Update general description of repeated capabilities.
ni-jfitzger Jan 28, 2022
e4ba124
Merge branch 'master' of https://github.com/ni-jfitzger/nimi-python i…
ni-jfitzger Apr 3, 2023
4fda89a
indexing is for repeated capability **instance**
ni-jfitzger Apr 3, 2023
948db7a
Remove commented section for non-0-length prefixes
ni-jfitzger Apr 3, 2023
f2dc5ea
Merge branch 'master' of https://github.com/ni-jfitzger/nimi-python i…
ni-jfitzger May 6, 2023
f04652c
Merge branch 'master' of https://github.com/ni-jfitzger/nimi-python i…
ni-jfitzger Jul 11, 2023
d48cfc9
generate correct snippets for nidigital
ni-jfitzger Jul 11, 2023
1cc9cf4
generate correct rep cap documentation for nidcpower
ni-jfitzger Jul 11, 2023
ce93c56
generate correct rep cap documentation for nifgen
ni-jfitzger Jul 11, 2023
8e8833c
merge indices, string_indices fields
ni-jfitzger Jul 11, 2023
cf13613
genereate correct rep cap documentation for niscope
ni-jfitzger Jul 11, 2023
76fede8
generate correct rep_cap documentation for niswitch
ni-jfitzger Jul 11, 2023
fb8c3a0
parameterize the new tests
ni-jfitzger Jul 11, 2023
ad59a96
reduce code duplication in new helper functions
ni-jfitzger Jul 11, 2023
30efefd
eliminate most rep cap example defaults
ni-jfitzger Jul 11, 2023
e461d65
Omit examples of elements and iterables at the top. Specify element t…
ni-jfitzger Jul 15, 2023
19b2208
Remove the "or errors if the value is not the same for all." statement
ni-jfitzger Jul 15, 2023
d2c61ae
like -> such as
ni-jfitzger Jul 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build/helper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
116 changes: 116 additions & 0 deletions build/helper/documentation_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
46 changes: 23 additions & 23 deletions build/templates/rep_caps.rst.mako
Original file line number Diff line number Diff line change
Expand Up @@ -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

Loading