Coverage for suhteita/robot/TicketSystemLibrary/ticket_system_bridge.py: 100.00%
59 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 22:42:46 +00:00
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 22:42:46 +00:00
1"""Ticket system abstraction relaying keywords to API methods of the underlying ticket system (JIRA)."""
3import ast
4from typing import List, no_type_check
6import jmespath
7import wrapt # type: ignore
8from robot.api import ContinuableFailure, logger
10from suhteita.ticket_system_actions import Jira as Ticket
13@no_type_check
14def _string_to_data(string):
15 """Parse the string into the underlying data type if successful else return the string."""
16 try:
17 return ast.literal_eval(str(string).strip())
18 except Exception:
19 return string
22@no_type_check
23@wrapt.decorator
24def _string_variables_to_data(function, instance, args, kwargs):
25 """Transform the string variables to data, relay to function, and return the call result."""
26 args = [_string_to_data(arg) for arg in args]
27 kwargs = dict((arg_name, _string_to_data(arg)) for arg_name, arg in kwargs.items())
28 return function(*args, **kwargs)
31@no_type_check
32class TicketSystemBridge(object):
33 """Use the robot framework hybrid API to proxy the calls and support discovery of keywords."""
35 ROBOT_LIBRARY_SCOPE = 'Global'
36 _ticket_system = Ticket
37 _session = None
39 def get_keyword_names(self) -> List[str]:
40 """Generate the list of keywords from the underlying provider - required hybrid API method."""
41 get_members = self._ticket_system.__dict__.items
42 kws = [name for name, function in get_members() if hasattr(function, '__call__')]
43 kws += ['extract_fields', 'extract_paths', 'extract_project_keys', 'ticket_session']
45 return [kw for kw in kws if not kw.startswith('delete_') and kw not in ('__init__', 'get_issue_remotelinks')]
47 @no_type_check
48 def ticket_session(self, url=None, username=None, password=None, **kwargs):
49 """Login and fetch the session object."""
50 self._session = self._ticket_system(url=url, username=username, password=password, **kwargs)
51 logger.debug('Connected to ticket system')
52 return self._session
54 @no_type_check
55 @staticmethod
56 def extract_fields(data, fields):
57 """Extract dictionary fields from data per key value (field name) to reduce the clutter in logs."""
58 try:
59 return {field: data[field] for field in fields}
60 except KeyError as err:
61 raise ContinuableFailure(f'Extraction of fields failed for (field=={err})')
63 @no_type_check
64 @staticmethod
65 def extract_paths(data, paths):
66 """Extract dictionary fields from data per paths to values to reduce the clutter in logs."""
67 return {path: jmespath.search(path.lstrip('/').replace('/', '.'), data) for path in paths}
69 @no_type_check
70 @staticmethod
71 def extract_project_keys(projects):
72 """Extract dictionary key field values from list of project dicts received per API."""
73 try:
74 return [project['key'] for project in projects]
75 except KeyError as err:
76 raise ContinuableFailure(f'Extraction of key field failed for projects (field=={err})')
78 @no_type_check
79 def __getattr__(self, name):
80 """Relay the function matching the keyword or the lookup error."""
81 func = None
82 if name in self._ticket_system.__dict__.keys():
83 func = getattr(self._ticket_system, name)
85 if func:
86 return _string_variables_to_data(func)
88 raise AttributeError(f'Keyword {name} does not exist or has been overridden by this library.')