########################################################################
##
# Imports needed for every Tooladapter
from tts.core.toolingFramework.interface.Descriptors import \
ToolDescriptor, PropertyDescriptor, JobDescriptor
from tts.core.toolingFramework.interface.Properties import \
PropertyTypeId
from tts.core.toolingFramework.interface.Capabilities import \
Toolcaps
##
from tts.core.toolingFramework.interface.AbstractAdapter import \
ToolAdapter
from tts.core.toolingFramework.interface.Exceptions import \
ToollibError
from tts.core.toolingFramework.interface.Proxy import \
ToolAdapterProxy
##
########################################################################
TOOLNAME = 'AdvancedExampleAdapter'
TOOLCAPS = Toolcaps.GetNull()
def IsInstalled():
"""
.. seealso:: :meth:`BasicExampleAdapter.IsInstalled()`
"""
return True
def CreateToolAdapter(host, port): # pylint: disable=unused-argument
"""
.. seealso:: :meth:`BasicExampleAdapter.CreateToolAdapter()`
"""
return ToolAdapterProxy(AdvancedExampleAdapter())
class AdvancedExampleAdapter(ToolAdapter): # pylint: disable=no-toollib
"""
Sample implementation of a ToolAdapter with additional feature.
"""
def __init__(self):
ToolAdapter.__init__(self)
self._toolDesc = ToolDescriptor(
TOOLNAME,
[], # must be an empty list
0,
# List of PropertyDescriptors:
[
# definition of first property group
PropertyDescriptor.CreateInstance(
name='choiceExampleGroup',
displayName='First property group',
type=PropertyTypeId.group,
),
# choice group inside the property group
# 'choiceExampleGroup'
PropertyDescriptor.CreateInstance(
name='choiceParameter',
displayName='Choice group parameter',
description='An example parameter',
type=PropertyTypeId.choiceGroup,
validReferences=None,
default='Value A',
domain=['Value A', 'Value B'],
group='choiceExampleGroup'
),
# property which is only displayed if 'Value A' is
# selected in the previous choice group
PropertyDescriptor.CreateInstance(
name='exampleCheckbox',
displayName='Check box for value A',
type=PropertyTypeId.bool,
default=True,
group='choiceParameter',
groupValue='Value A'
),
# Example property with int value
PropertyDescriptor.CreateInstance(
name='intParameter',
displayName='Example integer',
type=PropertyTypeId.int,
default=0,
),
],
# List of ToolJobs:
[
# Tooljob with a complex return/result type
JobDescriptor('GetCountryLanguageAndCurrency', [
PropertyDescriptor.CreateInstance(
name='country',
displayName='Country',
description=None,
type=PropertyTypeId.string,
domain=[
'Germany',
'Great Britain',
'France'
],
default='France'
),
],
'Demonstrates a grouped input parameter as well as '
'complex return types.',
# PropertyDescriptor for the return/result: For a
# complex return type the type of the result property
# should be a set to PropertyTypeId.object.
PropertyDescriptor.CreateInstance(
name='result',
description=None,
type=PropertyTypeId.object),
),
]
)
def OnConfigure(self):
"""
This method is called on tool start (test bench start, manual
start in configuration window). It can be used to start any
external tool needed by this ToolAdapter. Raise a ToollibError
to signal an error.
If OnConfigure fails, OnUnconfigure will not be called.
Use "pass" if no external tool is used.
"""
print(
f'Setting up tool connection for test bench settings choice '
f'parameter {self.GetProperty("choiceParameter")} '
f'and integer parameter '
f'{self.GetTypedProperty("intParameter")}.')
def OnUnconfigure(self):
"""
This method is called on tool shutdown, if the previous call to
OnConfigure did not fail. It can be used to stop any tool needed
by this ToolAdapter.
Raise a ToollibError to signal an error. Use "pass" if no
external tool is used.
"""
print('Disconnecting tool.')
def IsBroken(self):
"""
This method is called before test execution and on configuration
window update. Return True if any of the external tools used by
this ToolAdapter cannot be used anymore (e.g connection lost,
tool locked up). Otherwise or if no tool is used, return False.
:return: True if tool is broken (not usable)
:rtype: bool
"""
return False
def JobGetCountryLanguageAndCurrency(self, country):
"""
Example Tooljob with a complex return type, in this example a
tuple.
For complex return values the type of the corresponding
PropertyDescriptor for the return value needs to be set to
PropertyTypeId.object.
"""
if country == 'Germany':
return ['German', 'Euro']
if country == 'Great Britain':
return ['English', 'Pound sterling']
if country == 'France':
return ['French', 'Euro']
raise ValueError('Unknown country given')
def GetVersion(self):
"""
You can return the version of the tool you are connecting via
this tool adapter as a string. The version will be documented
in the test report.
:return: version
:rtype: Optional<str>
"""
return None
|
from __future__ import annotations
from typing import Literal
from collections.abc import Callable
#########################################################################
##
# No UserTool-specific imports needed
#
#
#
#
#
#
#
#
#
#
#
#
#
##
#########################################################################
# TOOLNAME and TOOLCAPS should no longer be set.
# The tool name now has to be defined in GetToolName()
# MODULE_TYPE = 'USER_TOOL' now required so that ecu.test can discover
# this module and recognize it as a user tool:
MODULE_TYPE = 'USER_TOOL'
# IsInstalled() should no longer be implemented.
# CreateToolAdapter() should no longer be implemented.
class AdvancedExampleAdapterUserTool: # Inheritance no longer needed
"""
Sample implementation of a ToolAdapter with additional feature.
"""
# The __init__() method now requires parameter "properties".
# It may contain startup functionality as it is now called on tool
# startup rather than ecu.test start.
def __init__(self, properties: dict[str, str | bool]) -> None:
"""
This method is called on tool start (test bench start, manual
start in configuration window). It can be used to start any
external tool needed by this ToolAdapter. Use `pass` if no
external tool is used.
:param properties: Dictionary with the properties from the test
bench configuration for this tool and the
configured values. The possible properties
are defined by the return value of the
:func:`GetProperties` method.
"""
# Description of properties and jobs are now handled within the
# separate methods GetToolname(), GetProperties() and GetJobs()
# The settings for properties in the TBC can now be accessed with
# the "properties" dict.
self._properties = properties
# Properties can be accessed from the dictionary.
try:
int(self._properties["Example integer"])
except ValueError:
raise ValueError(
f'Configured value '
f'{self._properties["Example integer"]} for parameter '
f'"intParameter" can not be converted to an integer.'
)
# OnConfigure() no longer needed:
# Startup functionality previously called in OnConfigure()
# may be moved to __init__().
print(
f'Setting up tool connection for test bench settings choice '
f'parameter {self._properties["Choice group parameter"]} '
f'and integer parameter '
f'{self._properties["Example integer"]}.'
)
# New method to indicate tool name
@classmethod
def GetToolName(cls) -> str:
"""
The name of the tool. This name is displayed in the test bench
configuration.
"""
return 'AdvancedExampleAdapter_UserTool'
# New optional method to define properties
@classmethod
def GetProperties(cls) -> dict[str, dict]:
"""
Properties of the tool. These properties can be configured in the
test bench configuration. The configured properties are passed to
the user tool when the configuration is started.
Available property types are STRING, BOOL and CHOICE.
"""
# Properties are now described as dictionaries.
# The complexity of PropertyDescriptors is no longer needed.
return {
'First property group': {
'Choice group parameter': {
'Description': 'An example parameter',
'Type': 'CHOICE',
'Choices': ['Value A', 'Value B'],
'Default': 'Value A',
},
'Check box for value A': {
'Description': 'Additional choice for Value A. '
'Will only be evaluated for '
'Choice group parameter Value A',
'Type': 'BOOL',
'Default': True,
# Property is always shown;
# groupValues not supported.
},
},
'Example integer': {
'Description': 'An example integer',
# Not supported types, e.g. previously 'int',
# need to be cast to the correct type upon usage.
'Type': 'STRING',
'Default': '0',
},
}
# New optional method to define jobs
@classmethod
def GetJobs(cls) -> list[Callable]:
"""
Provides a list of methods that are offered in ecu.test as a
tool job for this user tool. The implementation is optional.
Note: The properties of the tool job are generated using the
docstring and the Python type hints of the method.
:return: List of job methods.
"""
# A method is now interpreted as a job once it is returned by
# this method. A job method's name no longer needs to start with
# "Job".
# Also, jobs no longer need to be described with JobDescriptors.
# Instead, the job descriptions are derived from the job method's
# docstring.
return [cls.GetCountryLanguageAndCurrency]
# OnConfigure() is no longer used.
# Any startup sequences for the tool connection should be moved
# to __init__()
# Renamed method from OnUnconfigure()
def Dispose(self) -> None:
"""
This method is called on tool shutdown. It can be used to stop
any tool needed by this ToolAdapter.
Can be omitted if no external tool is used.
"""
print('Disconnecting tool.')
def IsBroken(self) -> bool:
"""
This method is called before test execution and on configuration
window update. Return True if any of the external tools used by
this ToolAdapter cannot be used anymore (e.g connection lost,
tool locked up). Otherwise or if no tool is used, return False.
:return: True if tool is broken (not usable)
:rtype: bool
"""
return False
def GetCountryLanguageAndCurrency( # Prefix "Job" no longer needed
self,
country: Literal['Germany', 'Great Britain', 'France'] = 'France'
) -> list[str]: # Domain defined with type hints
"""
Demonstrates a grouped input parameter as well as complex return
types.
:param country: Country whose information are to be checked.
Supported values are 'Germany', 'Great Britain',
'France'
:return:
"""
if country == 'Germany':
return ['German', 'Euro']
if country == 'Great Britain':
return ['English', 'Pound sterling']
if country == 'France':
return ['French', 'Euro']
raise ValueError('Unknown country given')
# GetVersion() now always requires a string return value.
def GetVersion(self) -> str:
"""
Version of the external tool. This version will be documented
in the test report.
"""
return '1.0.0'
|