def return_type(self, context: TelRootContext) -> TelType: if self._calculation_expr: return self._calculation_expr.return_type(context) elif self._taxon: return TelType.from_taxon_validation_type(self._taxon.validation_type) else: # Taxon is not set. That can happen only if the taxon is optional and out of data source scope # If taxon is required and out of scope, it will fail in validation step. return TelType(TelDataType.NONE_OPTIONAL)
def return_type(self, context: TelRootContext) -> TelType: types = [] if not self._left_invalid: types.append(self._left.return_type(context)) if not self._right_invalid: types.append(self._right.return_type(context)) if not types: types.append(TelType(TelDataType.ANY)) return TelType.return_common_type(types)
def __init__( self, pre_formulas: List[PreFormula] = None, post_formula=None, dimension_formulas: List[PreFormula] = None, data_source_formula_templates: List[SqlFormulaTemplate] = None, phase: TelPhase = TelPhase.any, used_taxons: Optional[UsedTaxonSlugsContainer] = None, invalid_value: bool = False, return_data_sources: Set[Optional[str]] = None, return_type: Optional[TelType] = None, template_slugs: Set[TaxonExpressionStr] = None, debug_info: Optional[Any] = None, override_mappings: Optional[OverrideMappingTelData] = None, ): self.pre_formulas = [] if pre_formulas is None else pre_formulas self.dimension_formulas = [] if dimension_formulas is None else dimension_formulas self.post_formula = post_formula self._output = [] self.used_taxons = used_taxons or UsedTaxonSlugsContainer() self.invalid_value = invalid_value self.return_data_sources = return_data_sources or set() self.return_type = return_type or TelType(TelDataType.ANY, is_constant=True) self.phase = phase self.data_source_formula_templates = data_source_formula_templates or [] self.template_slugs = template_slugs or set() self.debug_info = debug_info self.override_mappings = override_mappings or set()
def validate(self, context: TelValidationContext) -> TelValidationContext: super().validate(context) if not TelType.are_compatible_data_types( [self._left.return_type(context.root_context), self._right.return_type(context.root_context)] ): context.with_error('Operands in logical expression must have compatible data types', location=self.location) return context
def return_type(self, context: TelRootContext) -> TelType: types = [] if not self._left_invalid: types.append(self._left.return_type(context)) if not self._right_invalid: types.append(self._right.return_type(context)) return TelType.return_common_type(types).copy(data_type=TelDataType.BOOLEAN)
def test_tel_type_data_type(): assert TelType(TelDataType.STRING).is_string() assert TelType(TelDataType.INTEGER).is_integer() assert TelType(TelDataType.INTEGER).is_number() assert TelType(TelDataType.NUMERIC).is_number() assert TelType(TelDataType.DATETIME).is_date() assert TelType(TelDataType.DATETIME).is_datetime() assert TelType(TelDataType.BOOLEAN).is_boolean()
def test_tel_type_copy(): tel_type = TelType(TelDataType.ANY, is_constant=False) assert tel_type.copy().data_type is TelDataType.ANY assert tel_type.copy().is_constant is False assert tel_type.copy( data_type=TelDataType.STRING).data_type is TelDataType.STRING assert tel_type.copy(data_type=TelDataType.STRING).is_constant is False assert tel_type.copy(is_constant=True).data_type is TelDataType.ANY assert tel_type.copy(is_constant=True).is_constant is True assert tel_type.copy(data_type=TelDataType.STRING, is_constant=True).data_type is TelDataType.STRING assert tel_type.copy(data_type=TelDataType.STRING, is_constant=True).is_constant is True
def merge_with(self, other: 'ExprResult', with_type: bool = True): """ Helper fn to copy various values from other result to self. """ if self.invalid_value is False and other.invalid_value is False: # Copy the values only if source and target results are valid. self.used_taxons.update_from(other.used_taxons) self.data_source_formula_templates.extend( other.data_source_formula_templates) self.dimension_formulas.extend(other.dimension_formulas) self.pre_formulas.extend(other.pre_formulas) self.return_data_sources.update(other.return_data_sources) self.template_slugs.update(other.template_slugs) self.override_mappings.update(other.override_mappings) if with_type: self.return_type = TelType.return_common_type( [self.return_type, other.return_type])
def validate( self, position: int, fn_name: str, exprs: Optional[Iterable[TelExpression]], location: ParserRuleContext, context: TelValidationContext, ) -> TelValidationContext: if self._optional and not exprs: return context elif not self._optional and not exprs: return context.with_error( f'{fn_name} requires at least 1 argument', location=location) elif exprs and not TelType.are_compatible_data_types( [expr.return_type(context.root_context) for expr in exprs]): context.with_error( f'Arguments in function {fn_name} must have compatible data types', location=location) for expr in exprs: self._validate_phase(position, fn_name, expr, context) return context
def __call__(self, typ: TelType) -> bool: return typ.is_integer()
def __call__(self, typ: TelType) -> bool: return typ.is_number()
def __call__(self, typ: TelType) -> bool: return typ.is_string()
def return_type(self, context: TelRootContext) -> TelType: return TelType.return_common_type([ arg.return_type(context) for arg in self._args ]).copy(is_constant=False)
def test_tel_type_from_validation_type(): tel_type = TelType.from_taxon_validation_type(ValidationType.text) assert tel_type.data_type is TelDataType.STRING assert tel_type.is_constant is False
def test_tel_type_return_common_type(tel_types, expected_common_type): assert TelType.return_common_type( tel_types).data_type is expected_common_type.data_type assert TelType.return_common_type( tel_types).is_constant is expected_common_type.is_constant
def __call__(self, typ: TelType) -> bool: return typ.is_number() or typ.is_string() or typ.is_boolean()
def return_type(self, context: TelRootContext) -> TelType: return TelType(self._data_type, is_constant=True)
def test_tel_type_constant(): assert TelType(TelDataType.ANY, is_constant=True).is_constant assert not TelType(TelDataType.ANY, is_constant=False).is_constant
def return_type(self, context: TelRootContext) -> TelType: return TelType(TelDataType.UNKNOWN, False)
def __call__(self, typ: TelType) -> bool: return typ.is_datetime()
def __call__(self, typ: TelType) -> bool: return typ.is_boolean()
def test_tel_type_compatible_data_types(tel_types, expected_compatibility): assert TelType.are_compatible_data_types( tel_types) is expected_compatibility
def __call__(self, typ: TelType) -> bool: return typ.is_number() or typ.is_string() or typ.is_datetime()
is_constant=True).data_type is TelDataType.STRING assert tel_type.copy(data_type=TelDataType.STRING, is_constant=True).is_constant is True def test_tel_type_from_validation_type(): tel_type = TelType.from_taxon_validation_type(ValidationType.text) assert tel_type.data_type is TelDataType.STRING assert tel_type.is_constant is False @pytest.mark.parametrize( "tel_types,expected_common_type", [ ([], TelType(TelDataType.UNKNOWN)), ([TelType(TelDataType.UNKNOWN)], TelType(TelDataType.UNKNOWN)), ([TelType(TelDataType.UNKNOWN), TelType(TelDataType.UNKNOWN)], TelType(TelDataType.UNKNOWN)), ([TelType(TelDataType.UNKNOWN), TelType(TelDataType.ANY)], TelType(TelDataType.UNKNOWN)), ([TelType(TelDataType.UNKNOWN), TelType(TelDataType.STRING)], TelType(TelDataType.UNKNOWN)), ([TelType(TelDataType.NONE_OPTIONAL)], TelType(TelDataType.ANY)), ([ TelType(TelDataType.NONE_OPTIONAL), TelType(TelDataType.NONE_OPTIONAL) ], TelType(TelDataType.ANY)), ([TelType(TelDataType.NONE_OPTIONAL), TelType(TelDataType.ANY)], TelType(TelDataType.ANY)), ([TelType(TelDataType.NONE_OPTIONAL),