def _build_dynamic_choice_list_filter(spec, report): wrapped = DynamicChoiceListFilterSpec.wrap(spec) choice_provider_spec = wrapped.get_choice_provider_spec() choice_provider = FilterChoiceProviderFactory.from_spec( choice_provider_spec)(report, wrapped.slug) choice_provider.configure(choice_provider_spec) invalid_spec = (wrapped.ancestor_expression and not set( wrapped.ancestor_expression.keys()) == set(['field', 'location_type'])) if invalid_spec: raise BadSpecError( _("'ancestor_expression' must be empty dictionary or have 'field', 'location_type' keys" )) if wrapped.ancestor_expression and not isinstance(choice_provider, LocationChoiceProvider): raise BadSpecError( _("'ancestor_expression' is applicable only for location choices")) return DynamicChoiceListFilter( name=wrapped.slug, datatype=wrapped.datatype, field=wrapped.field, label=wrapped.display, show_all=wrapped.show_all, url_generator=dynamic_choice_list_url, choice_provider=choice_provider, ancestor_expression=wrapped.ancestor_expression, )
def validate_spec(self, spec): if 'type' not in spec: raise BadSpecError( _('Indicator specification must include a root level type field.' )) elif spec['type'] not in self.constructor_map: raise BadSpecError( _('Illegal indicator type: "{0}", must be one of the following choice: ({1})' .format(spec['type'], ', '.join(self.constructor_map))))
def get_whens(self): whens = [] for value, bounds in self.ranges.items(): if len(bounds) != 2: raise BadSpecError('Range must contain 2 items, contains {}'.format(len(bounds))) try: bounds = [int(b) for b in bounds] except ValueError: raise BadSpecError('Invalid range: [{}, {}]'.format(bounds[0], bounds[1])) whens.append([self._base_expression(bounds), bindparam(None, value)]) return whens
def from_spec(cls, spec): if spec.get('type') not in cls.spec_map: raise BadSpecError(_('Illegal chart type: {0}, must be one of the following choice: ({1})').format( spec.get('type', _('(missing from spec)')), ', '.join(cls.spec_map) )) try: return cls.spec_map[spec['type']].wrap(spec) except BadValueError as e: raise BadSpecError(_('Problem creating chart from spec: {}, message is: {}').format( json.dumps(spec, indent=2), str(e), ))
def from_spec(cls, spec, context=None): try: return cls.spec_map[spec['type']](spec, context) except KeyError: raise BadSpecError(_('Invalid or missing getter type: {}. Valid options are: {}').format( spec.get('type', '[missing]'), ', '.join(cls.spec_map.keys()), )) except BadValueError as e: raise BadSpecError(_('Problem creating getter: {}. Message is: {}').format( json.dumps(spec, indent=2), str(e), ))
def get_transform(cls, spec): try: return cls.spec_map[spec['type']].wrap(spec) except KeyError: raise BadSpecError(_('Invalid or missing transform type: {}. Valid options are: {}').format( spec.get('type', None), ', '.join(cls.spec_map.keys()), )) except BadValueError as e: raise BadSpecError(_('Problem creating transform: {}. Message is: {}').format( json.dumps(spec, indent=2), str(e), ))
def validate_db_config(self): mirrored_engine_ids = self.mirrored_engine_ids if not mirrored_engine_ids: return if self.engine_id in mirrored_engine_ids: raise BadSpecError("mirrored_engine_ids list should not contain engine_id") for engine_id in mirrored_engine_ids: if not connection_manager.engine_id_is_available(engine_id): raise BadSpecError( "DB for engine_id {} is not availble".format(engine_id) ) if not connection_manager.resolves_to_unique_dbs(mirrored_engine_ids + [self.engine_id]): raise BadSpecError("No two engine_ids should point to the same database")
def from_spec(cls, spec): column_type = spec.get('type') or 'field' if column_type not in cls.class_map: raise BadSpecError( 'Unknown or missing column type: {} must be in [{}]'.format( column_type, ', '.join(cls.class_map))) try: return cls.class_map[column_type].wrap(spec) except BadValueError as e: raise BadSpecError( _('Problem creating column from spec: {}, message is: {}'). format( json.dumps(spec, indent=2), str(e), ))
def _build_compound_filter(spec, context): compound_type_map = { 'or': ORFilter, 'and': ANDFilter, } if spec['type'] not in compound_type_map: raise BadSpecError(_('Complex filter type {0} must be one of the following choices ({1})').format( spec['type'], ', '.join(compound_type_map) )) elif not isinstance(spec.get('filters'), list): raise BadSpecError(_('{0} filter type must include a "filters" list'.format(spec['type']))) filters = [FilterFactory.from_spec(subspec, context) for subspec in spec['filters']] return compound_type_map[spec['type']](filters)
def by_id(cls, config_id, domain=None): """ Returns a ReportConfiguration object, NOT StaticReportConfigurations. :param domain: Optionally specify domain name to validate access. Raises ``DocumentNotFound`` if domains don't match. """ mapping = cls.by_id_mapping() if config_id not in mapping: mapping = cls.by_id_mapping(rebuild=True) metadata = mapping.get(config_id, None) if not metadata: raise BadSpecError( _('The report configuration referenced by this report could ' 'not be found.')) config = cls._get_from_metadata(metadata) if domain and config.domain != domain: raise DocumentNotFound( "Document {} of class {} not in domain {}!".format( config_id, config.__class__.__name__, domain, )) return config
def from_spec(cls, spec, context=None): cls.validate_spec(spec) try: return cls.constructor_map[spec['type']](spec, context) except BadValueError as e: # for now reraise jsonobject exceptions as BadSpecErrors raise BadSpecError(str(e))
def wrap(self, obj): if 'constant' not in obj: raise BadSpecError( '"constant" property is required in object beginning with <pre>{}</pre>' .format(textwrap.shorten(str(obj), width=75, placeholder="..."))) return super(ConstantGetterSpec, self).wrap(obj)
def from_spec(cls, spec): column_type = spec.get('type') or 'field' if column_type not in cls.class_map: raise BadSpecError( 'Unknown or missing column type: {} must be in [{}]'.format( column_type, ', '.join(cls.class_map.keys()))) return cls.class_map[column_type].wrap(spec)
def configure(self, compiled_properties): for key in compiled_properties: if not isinstance(key, (six.text_type, bytes)): raise BadSpecError("Properties in a dict expression must be strings!") if six.PY3: soft_assert_type_text(key) self._compiled_properties = compiled_properties
def validate_spec(cls, spec): if spec.get('type') not in cls.constructor_map: raise BadSpecError( _('Illegal report filter type: {0}, must be one of the following choice: ({1})').format( spec.get('type', _('(missing from spec)')), ', '.join(cls.constructor_map.keys()) ) )
def from_spec(cls, spec, context=None): if _is_literal(spec): return cls.from_spec(_convert_constant_to_expression_spec(spec), context) try: return cls.spec_map[spec['type']](spec, context) except KeyError: raise BadSpecError(_('Invalid or missing getter type: {} for expression: {}. ' 'Valid options are: {}').format( spec.get('type', '[missing]'), spec, ', '.join(cls.spec_map.keys()), )) except (TypeError, BadValueError) as e: raise BadSpecError(_('Problem creating getter: {}. Message is: {}').format( json.dumps(spec, indent=2, default=json_handler), str(e), ))
def validate_spec(self, spec): if spec.get('type') not in self.constructor_map: raise BadSpecError( _('Illegal or missing filter type: "{0}", must be one of the following choice: ({1})'.format( spec.get('type'), ', '.join(self.constructor_map) )) )
def report_class_by_domain_and_id(cls, domain, config_id): for wrapped, path in cls._all(): if cls.get_doc_id(domain, wrapped.report_id, wrapped.custom_configurable_report) == config_id: return wrapped.custom_configurable_report raise BadSpecError( _('The report configuration referenced by this report could ' 'not be found.'))
def configure(self, doc_id_expression, value_expression): non_couch_doc_types = (LOCATION_DOC_TYPE,) if (self.related_doc_type not in non_couch_doc_types and get_db_by_doc_type(self.related_doc_type) is None): raise BadSpecError('Cannot determine database for document type {}!'.format(self.related_doc_type)) self._doc_id_expression = doc_id_expression self._value_expression = value_expression
def by_id(cls, config_id): """ Returns a ReportConfiguration object, NOT CustomReportConfigurations. """ for ds in cls.all(): if ds.get_id == config_id: return ds raise BadSpecError(_('The report configuration referenced by this report could ' 'not be found.'))
def get_operator(slug): try: return OPERATORS[slug.lower()] except KeyError: raise BadSpecError( '{0} is not a valid operator. Choices are {1}'.format( slug, ', '.join(OPERATORS.keys()), ))
def _check_for_duplicates(supposedly_unique_list, error_msg): # http://stackoverflow.com/questions/9835762/find-and-list-duplicates-in-python-list duplicate_items = set([ item for item in supposedly_unique_list if supposedly_unique_list.count(item) > 1 ]) if len(duplicate_items) > 0: raise BadSpecError( _(error_msg).format(', '.join(sorted(duplicate_items))))
def from_spec(cls, spec, report=None): cls.validate_spec(spec) try: return cls.constructor_map[spec['type']](spec, report) except (AssertionError, BadValueError) as e: raise BadSpecError(_('Problem creating report filter from spec: {}, message is: {}').format( json.dumps(spec, indent=2), str(e), ))
def configure(self, doc_id_expression, value_expression): if get_db_by_doc_type(self.related_doc_type) is None: raise BadSpecError( u'Cannot determine database for document type {}!'.format( self.related_doc_type)) self._doc_id_expression = doc_id_expression self._value_expression = value_expression # used in caching self._vary_on = json.dumps(self.value_expression, sort_keys=True)
def validate(self, required=True): super(DataSourceConfiguration, self).validate(required) # these two properties implicitly call other validation self._get_main_filter() self._get_deleted_filter() # validate indicators and column uniqueness columns = [c.id for c in self.indicators.get_columns()] unique_columns = set(columns) if len(columns) != len(unique_columns): for column in set(columns): columns.remove(column) raise BadSpecError(_('Report contains duplicate column ids: {}').format(', '.join(set(columns)))) if self.referenced_doc_type not in VALID_REFERENCED_DOC_TYPES: raise BadSpecError( _('Report contains invalid referenced_doc_type: {}').format(self.referenced_doc_type)) self.parsed_expression
def by_id(cls, config_id): """ Returns a DataSourceConfiguration object, NOT a CustomDataSourceConfiguration. """ for ds in cls.all(): if ds.get_id == config_id: return ds raise BadSpecError(_('The data source referenced by this report could ' 'not be found.'))
def pk_columns(self): columns = [] for col in self.get_columns(): if col.is_primary_key: column_name = decode_column_name(col) columns.append(column_name) if self.sql_settings.primary_key: if set(columns) != set(self.sql_settings.primary_key): raise BadSpecError("Primary key columns must have is_primary_key set to true", self.data_source_id) columns = self.sql_settings.primary_key return columns
def from_spec(cls, spec, is_static, domain=None): column_type = spec.get('type') or 'field' if column_type not in cls.class_map: raise BadSpecError( 'Unknown or missing column type: {} must be in [{}]'.format( column_type, ', '.join(cls.class_map))) column_class = cls.class_map[column_type] if column_class.restricted_to_static(domain) and not ( is_static or settings.UNIT_TESTING): raise BadSpecError( "{} columns are only available to static report configs". format(column_type)) try: return column_class.wrap(spec) except BadValueError as e: raise BadSpecError( _('Problem creating column from spec: {}, message is: {}'). format( json.dumps(spec, indent=2), str(e), ))
def make_template(cls, spec): if spec.get('type') not in cls.spec_map: raise BadSpecError( _('Illegal sum_when_template type: "{0}", must be in: ({1})'). format(spec.get('type'), ', '.join(cls.spec_map))) try: template = cls.spec_map[spec['type']].wrap(spec) except BadValueError as e: raise BadSpecError( _('Problem creating template: {}, message is: {}').format( json.dumps(spec, indent=2), str(e), )) expected = template.bind_count() actual = len(template.binds) if expected != actual: raise BadSpecError( _('Expected {} binds in sum_when_template {}, found {}'). format(expected, spec['type'], actual)) return template
def report_class_by_domain_and_id(cls, domain, config_id): try: report_domain, wrapped = cls.by_id_mapping()[config_id] except KeyError: raise BadSpecError( _('The report configuration referenced by this report could not be found.') ) if report_domain != domain: raise DocumentNotFound("Document {} of class {} not in domain {}!".format( config_id, ReportConfiguration.__class__.__name__, domain, )) return wrapped.custom_configurable_report