Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ nidcpowerunittest.xml
nidigitalunittest.xml
nifakeunittest.xml
nimodinstunittest.xml
nirfsgunittest.xml
niscopeunittest.xml
nitclkunittest.xml
codegen.xml
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,7 @@
#### [nirfsg] Unreleased
- Added
- Enabled selected public APIs
- Enabled custom object expansion for repeated capabilities
- Basic example
- Documentation for APIs (not final)
- Changed
Expand Down
1 change: 1 addition & 0 deletions build/helper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from build.helper.metadata_filters import filter_library_functions # noqa: F401
from build.helper.metadata_filters import filter_parameters # noqa: F401
from build.helper.metadata_filters import filter_public_functions # noqa: F401
from build.helper.metadata_filters import filter_rep_cap_supported_attributes # noqa: F401

from build.helper.metadata_find import find_custom_type # noqa: F401
from build.helper.metadata_find import find_session_handle_parameter # noqa: F401
Expand Down
6 changes: 5 additions & 1 deletion build/helper/documentation_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .documentation_snippets import enum_note_text
from .documentation_snippets import func_note_text
from .documentation_snippets import rep_cap_attr_desc
from .documentation_snippets import rep_cap_attr_desc_without_global
from .documentation_snippets import rep_cap_method_desc
from .helper import get_array_type_for_api_type
from .helper import get_numpy_type_for_api_type
Expand Down Expand Up @@ -116,7 +117,10 @@ def add_attribute_rep_cap_tip(attr, config):

multi_capability = get_attribute_repeated_caps_with_conjunction(attr)
single_capability = attr['supported_rep_caps'][0]
attr['documentation']['tip'] = rep_cap_attr_desc.format(config['module_name'], multi_capability, single_capability, attr['python_name'])
if config['repeated_capability_object_type']['python'] != 'applicable-attributes-only':
attr['documentation']['tip'] = rep_cap_attr_desc.format(config['module_name'], multi_capability, single_capability, attr['python_name'])
else:
attr['documentation']['tip'] = rep_cap_attr_desc_without_global.format(config['module_name'], multi_capability, single_capability, attr['python_name'])


def get_documentation_for_node_rst(node, config, indent=0):
Expand Down
7 changes: 7 additions & 0 deletions build/helper/documentation_snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
Example: :py:attr:`my_session.{3}`
'''

rep_cap_attr_desc_without_global = '''
This property can be set/get on specific {1} within your :py:class:`{0}.Session` instance.
Use Python index notation on the repeated capabilities container {1} to specify a subset.

Example: :py:attr:`my_session.{2}[ ... ].{3}`
'''

func_note_text = '''
One or more of the referenced functions are not in the Python API for this driver.
'''
Expand Down
3 changes: 3 additions & 0 deletions build/helper/metadata_add_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,9 @@ def add_all_config_metadata(config):
if 'uses_nitclk' not in config:
config['uses_nitclk'] = False

if 'repeated_capability_object_type' not in config:
config['repeated_capability_object_type'] = {'python': 'session'}

return config


Expand Down
13 changes: 13 additions & 0 deletions build/helper/metadata_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,16 @@ def filter_codegen_enums(enums):
return {k: v for k, v in enums.items() if v['codegen_method'] != 'no'}


def filter_rep_cap_supported_attributes(attributes, rep_cap_name):
'''Returns attribute metadata only for those attributes that support the specified repeated capability.

Args:
attributes: Dictionary of attribute metadata.

rep_cap_name: The name of the repeated capability to filter by.

Returns:
Dictionary of attributes that support the specified repeated capability.
'''
return {k: v for k, v in attributes.items() if rep_cap_name in v.get('supported_rep_caps', [])}

76 changes: 76 additions & 0 deletions build/templates/session.py.mako
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ${template_parameters['encoding_tag']}
<%
import build.helper as helper
import os
from string import capwords

grpc_supported = template_parameters['include_grpc_support']

Expand Down Expand Up @@ -33,7 +34,9 @@ from functools import wraps
% if attributes:
import ${module_name}._attributes as _attributes
% endif
% if config['repeated_capability_object_type']['python'] != 'applicable-attributes-only':
import ${module_name}._converters as _converters
% endif
import ${module_name}._library_interpreter as _library_interpreter
import ${module_name}.enums as enums
import ${module_name}.errors as errors
Expand Down Expand Up @@ -91,6 +94,72 @@ class _Lock(object):

% endif
% if len(config['repeated_capabilities']) > 0:
% if config['repeated_capability_object_type']['python'] == 'applicable-attributes-only':
class _RepeatedCapabilityAttributeOnlyBase(object):
def __init__(self, session, prefix):
object.__setattr__(self, '_session', session)
object.__setattr__(self, '_prefix', prefix)
object.__setattr__(self, '_repeated_capability', '')

def _get_attribute_vi_real64(self, attribute):
value = self._session._interpreter.get_attribute_vi_real64(self._prefix + self._repeated_capability, attribute)
return value

def _set_attribute_vi_real64(self, attribute, value):
self._session._interpreter.set_attribute_vi_real64(self._prefix + self._repeated_capability, attribute, value)

def _get_attribute_vi_int32(self, attribute):
value = self._session._interpreter.get_attribute_vi_int32(self._prefix + self._repeated_capability, attribute)
return value

def _set_attribute_vi_int32(self, attribute, value):
self._session._interpreter.set_attribute_vi_int32(self._prefix + self._repeated_capability, attribute, value)

def _get_attribute_vi_string(self, attribute):
value = self._session._interpreter.get_attribute_vi_string(self._prefix + self._repeated_capability, attribute)
return value

def _set_attribute_vi_string(self, attribute, value):
self._session._interpreter.set_attribute_vi_string(self._prefix + self._repeated_capability, attribute, value)


% for rep_cap in config['repeated_capabilities']:
class _RepeatedCapability${capwords(rep_cap['python_name'].replace('_', ' ')).replace(' ', '')}(_RepeatedCapabilityAttributeOnlyBase):
% for attribute in helper.sorted_attrs(helper.filter_rep_cap_supported_attributes(attributes, rep_cap['python_name'])):
<%
helper.add_attribute_rep_cap_tip(attributes[attribute], config)
%>\
% if attributes[attribute]['enum']:
% if helper.enum_uses_converter(enums[attributes[attribute]['enum']]):
${attributes[attribute]['python_name']} = _attributes.AttributeEnumWithConverter(_attributes.AttributeEnum(_attributes.Attribute${attributes[attribute]['type']}, enums.${enums[attributes[attribute]['enum']]['python_name']}, ${attribute}), _converters.${enums[attributes[attribute]['enum']]['enum_to_converted_value_function_name']}, _converters.${enums[attributes[attribute]['enum']]['converted_value_to_enum_function_name']})
% else:
${attributes[attribute]['python_name']} = _attributes.AttributeEnum(_attributes.Attribute${attributes[attribute]['type']}, enums.${enums[attributes[attribute]['enum']]['python_name']}, ${attribute})
% endif
% else:
${attributes[attribute]['python_name']} = _attributes.${attributes[attribute]['attribute_class']}(${attribute})
% endif
% if 'documentation' in attributes[attribute] and len(helper.get_documentation_for_node_docstring(attributes[attribute], config, indent=4).strip()) > 0:
'''Type: ${attributes[attribute]['type_in_documentation']}

${helper.get_documentation_for_node_docstring(attributes[attribute], config, indent=4)}
'''
% endif
% endfor
def __init__(self, session):
super(_RepeatedCapability${capwords(rep_cap['python_name'].replace('_', ' ')).replace(' ', '')}, self).__init__(session, '${rep_cap["prefix"]}')

def __setattr__(self, key, value):
if key not in dir(self):
raise AttributeError("'{0}' object has no attribute '{1}'".format(type(self).__name__, key))
object.__setattr__(self, key, value)

def __getitem__(self, repeated_capability):
super(_RepeatedCapability${capwords(rep_cap['python_name'].replace('_', ' ')).replace(' ', '')}, self).__setattr__('_repeated_capability', repeated_capability)
return self


% endfor
% else:
class _RepeatedCapabilities(object):
def __init__(self, session, prefix, current_repeated_capability_list):
self._session = session
Expand Down Expand Up @@ -128,6 +197,7 @@ class _NoChannel(object):
self._session._repeated_capability = self._repeated_capability_cache


% endif
% endif
class _SessionBase(object):
'''Base class for all ${config['driver_name']} sessions.'''
Expand All @@ -136,6 +206,7 @@ class _SessionBase(object):
_is_frozen = False

% for attribute in helper.sorted_attrs(helper.filter_codegen_attributes(attributes)):
% if not ('supported_rep_caps' in attributes[attribute] and len(attributes[attribute]['supported_rep_caps']) > 0 and config['repeated_capability_object_type']['python'] == 'applicable-attributes-only'):
<%
helper.add_attribute_rep_cap_tip(attributes[attribute], config)
%>\
Expand All @@ -154,6 +225,7 @@ helper.add_attribute_rep_cap_tip(attributes[attribute], config)
${helper.get_documentation_for_node_docstring(attributes[attribute], config, indent=4)}
'''
% endif
% endif
% endfor
<%
init_function = config['functions']['_init_function']
Expand All @@ -179,7 +251,11 @@ constructor_params = helper.filter_parameters(init_function['parameters'], helpe
% if len(config['repeated_capabilities']) > 0:
# Instantiate any repeated capability objects
% for rep_cap in config['repeated_capabilities']:
% if config['repeated_capability_object_type']['python'] == 'applicable-attributes-only':
self.${rep_cap['python_name']} = _RepeatedCapability${capwords(rep_cap['python_name'].replace('_', ' ')).replace(' ', '')}(self)
% else:
self.${rep_cap['python_name']} = _RepeatedCapabilities(self, '${rep_cap["prefix"]}', repeated_capability_list)
% endif
% endfor

% endif
Expand Down
3 changes: 3 additions & 0 deletions build/unit_tests/test_metadata_add_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,9 @@ def _compare_dicts(actual, expected):
},
],
'enum_whitelist_suffix': ['_POINT_FIVE'],
'repeated_capability_object_type': {
'python': 'session'
},
'repeated_capabilities': [
{'python_name': 'channels', 'prefix': '', },
],
Expand Down
Loading