Source code for swimlane.core.resources.report

import pendulum
import json 


from swimlane.core.cursor import PaginatedCursor
from swimlane.core.fields.list import ListField
from swimlane.core.resources.base import APIResource
from swimlane.core.resources.record import Record, record_factory
from swimlane.core.search import CONTAINS, EQ, EXCLUDES, NOT_EQ, LT, GT, LTE, GTE, ASC, DESC
from swimlane.utils import validate_type

ALLOWED_OPERATORS = ['Or', 'And']


[docs]class Report(APIResource, PaginatedCursor): """A report class used for searching Can be iterated over to retrieve results Notes: Record retrieval is lazily evaluated and cached internally, adding a filter and attempting to iterate again will not respect the additional filter and will return the same set of records each time Examples: Lazy retrieval of records with direct iteration over report :: report = app.reports.build('new-report') report.filter('field_1', 'equals', 'value') for record in report: do_thing(record) Full immediate retrieval of all records :: report = app.reports.build('new-report') report.filter('field_1', 'doesNotEqual', 'value') records = list(report) Attributes: name (str): Report name Keyword Args: limit (int): Max number of records to return from report/search page_size (int): Max number of records per page keywords (list(str)): List of keywords to use in report/search """ _type = "Core.Models.Search.StatsReport, Core" _FILTER_OPERANDS = ( EQ, NOT_EQ, CONTAINS, EXCLUDES, LT, GT, LTE, GTE ) _SORT_ORDERS = ( ASC, DESC ) default_limit = 50 default_page_start = None default_page_end = None def __init__(self, app, raw, **kwargs): APIResource.__init__(self, app._swimlane, raw) PaginatedCursor.__init__(self, limit=kwargs.pop('limit', self.default_limit), page_size=kwargs.pop('page_size', self.default_page_size), page_start=kwargs.pop('page_start', self.default_page_start), page_end=kwargs.pop('page_end', self.default_page_end) ) self.name = self._raw['name'] self.keywords = kwargs.pop('keywords', []) self._app = app for field_id in self._app._fields_by_id.keys(): self._raw['columns'].append(field_id)
[docs] def filter_type(self, filter_type): filter_type = filter_type.capitalize() self.validateOperator(filter_type) self.filter_type = filter_type
[docs] def validateOperator(self, operator): if operator not in ALLOWED_OPERATORS: raise ValueError('filter_type value not allowed')
def __str__(self): return self.name def _retrieve_raw_elements(self, page): body = self._raw.copy() body['pageSize'] = self.page_size body['offset'] = page if(type(self.filter_type) is str): body['filterType'] = self.filter_type body['keywords'] = ', '.join(self.keywords) response = self._swimlane.request('post', 'search', json=body) return response.json()['results'].get(self._app.id, []) def _parse_raw_element(self, raw_element): return Record(self._app, raw_element)
[docs] def filter(self, field_name, operand, value): """Adds a filter to report Notes: 1. All filters are currently AND'ed together. 2. None values work like a wildcard and will skip type verification. Args: field_name (str): Target field name to filter on operand (str): Operand used in comparison. See `swimlane.core.search` for options value: Target value used in comparison """ if operand not in self._FILTER_OPERANDS: raise ValueError('Operand must be one of {}'.format(', '.join(self._FILTER_OPERANDS))) field = self._get_stub_field(field_name) validate_type(field, value) value = self.parse_field_value(field, value) self._raw['filters'].append({ "fieldId": field.id, "filterType": operand, "value": field.get_report(value) })
[docs] def sort(self, field_name, order): """Adds a sort to report Args: field_name (str): Target field name to sort by order (str): Sort order """ if (order not in self._SORT_ORDERS): raise ValueError('Order must be one of {}'.format(', '.join(self._SORT_ORDERS))) field = self._get_stub_field(field_name) self._raw['sorts'][field.id] = order
[docs] def set_columns(self, *field_names): """Set specified columns for report Notes: The Tracking Id column is always included Args: *field_names (str): Zero or more column names """ self._raw['columns'] = [] for field_name in field_names: field = self._get_stub_field(field_name) self._raw['columns'].append(field.id) if self._app.tracking_id not in self._raw['columns']: self._raw['columns'].append(self._app.tracking_id)
def _get_stub_field(self, field_name): if not field_name or not isinstance(field_name, str): raise ValueError('field_name is of an invalid format, expected non-empty string') # Use temp Record instance for target app to translate values into expected API format record_stub = record_factory(self._app) return record_stub.get_field(field_name)
[docs] def parse_field_value(self, field, value): if isinstance(field, ListField): type = self.get_field_list_type(field.input_type) value = self.get_default_value(value, field.input_type) if isinstance(field, ListField) and not isinstance(value, list) and value is not None: self.validate_type(value, type, field.input_type) return [value] elif isinstance(field, ListField) and isinstance(value, list) and any(not isinstance(elem, type) for elem in value): raise TypeError('Field item must be a {}.'.format(field.input_type)) return value
[docs] def validate_type(self, value, type, type_name=None): if(not type_name): type_name = type if not isinstance(value, type): raise TypeError('Field must be a {}.'.format(type_name))
[docs] def get_default_value(self, value, field_type): if(value == '' and field_type == 'text'): value = None return value
[docs] def get_field_list_type(self, field_type): if field_type == 'text': return str elif field_type == 'numeric': return (int, float)
[docs]def report_factory(app, report_name, **kwargs): """Report instance factory populating boilerplate raw data Args: app (App): Swimlane App instance report_name (str): Generated Report name Keyword Args **kwargs: Kwargs to pass to the Report class """ # pylint: disable=protected-access created = pendulum.now().to_rfc3339_string() user_model = app._swimlane.user.as_usergroup_selection() return Report( app, { "$type": Report._type, "groupBys": [], "aggregates": [], "applicationIds": [app.id], "columns": [], "sorts": { "$type": "System.Collections.Generic.Dictionary`2" "[[System.String, mscorlib]," "[Core.Models.Search.SortTypes, Core]], mscorlib", }, "filters": [], "defaultSearchReport": False, "allowed": [], "permissions": { "$type": "Core.Models.Security.PermissionMatrix, Core" }, "createdDate": created, "modifiedDate": created, "createdByUser": user_model, "modifiedByUser": user_model, "id": None, "name": report_name, "disabled": False, "keywords": "" }, **kwargs )