Esempio n. 1
0
    def initialize(self, ctx):

        super().initialize(ctx)

        if self.path is None:
            raise ETLConfigurationException("Missing path attribute for %s" %
                                            self)
Esempio n. 2
0
    def initialize(self, ctx):
        super().initialize(ctx)

        if len(self.steps) <= 0:
            raise ETLConfigurationException("Union with no steps.")

        for p in self.steps:
            ctx.comp.initialize(p)
Esempio n. 3
0
 def initialize(self, comp):
     if (not self.is_initialized(comp)):
         logger.debug("Initializing %s" % (comp, ))
         self.component_desc(comp).initialized = True
         comp.initialize(self.ctx)
         try:
             pass
         except AttributeError as e:
             raise ETLConfigurationException("Tried to initialize invalid component (%s): %s" % (comp, e))
Esempio n. 4
0
    def include(self, configfile):
        configfile = self.interpolate(configfile)

        # Import only once
        abspath = os.path.abspath(configfile)
        if abspath in self.included_files:
            return
        self.included_files.append(abspath)

        logger.info("Including config file: %s", configfile)
        spec = importlib.util.spec_from_file_location("configmodule",
                                                      configfile)
        configmodule = importlib.util.module_from_spec(spec)
        try:
            spec.loader.exec_module(configmodule)
        except FileNotFoundError as e:
            raise ETLConfigurationException(
                "Config include file not found: %s" % (configfile))
        except Exception as e:
            raise ETLConfigurationException(
                "An error ocurred while loading '%s' config file: %s" %
                (configfile, e))
        configmodule.cubetl_config(self)
Esempio n. 5
0
    def initialize(self, ctx):

        super(FactDimension, self).initialize(ctx)
        ctx.comp.initialize(self.fact)

        if (len(self.attributes) > 0):
            raise Exception(
                "Cannot define attributes for a FactDimension (it's defined by the linked fact)"
            )

        self.dimensions = self.fact.dimensions
        self.measures = self.fact.measures
        self.attributes = self.fact.attributes

        if self.name != self.fact.name:
            raise ETLConfigurationException(
                "FactDimension %s name is '%s' but it should match name of fact %s ('%s')"
                % (self, self.name, self.fact, self.fact.name))
Esempio n. 6
0
    def _mappings(self, ctx):

        mappings = [mapping.copy() for mapping in self.mappings]
        for mapping in mappings:
            if (not "entity" in mapping):
                mapping["entity"] = self.entity

        for dimension in self.entity.dimensions:
            #if (not dimension.name in [mapping["name"] for mapping in self.mappings]):
            dimension_mapper = self.olapmapper.entity_mapper(dimension)
            dimension_mappings = dimension_mapper._mappings_join(ctx)

            # TODO: Check if entity/attribute is already mapped?
            self._extend_mappings(ctx, mappings, dimension_mappings)

        for measure in self.entity.measures:
            self._extend_mappings(ctx, mappings, [{
                "name":
                measure["name"],
                "type":
                measure["type"] if
                ("type" in measure and measure["type"] != None) else "Float",
                "entity":
                self.entity
            }])
        for attribute in self.entity.attributes:
            try:
                self._extend_mappings(ctx, mappings, [{
                    "name": attribute["name"],
                    "type": attribute["type"],
                    "entity": self.entity
                }])
            except KeyError as e:
                raise ETLConfigurationException(
                    "Definition of attribute %s of %s is missing %s" %
                    (attribute, self.entity, e))

        self._ensure_mappings(ctx, mappings)
        return mappings
Esempio n. 7
0
 def initialize(self, ctx):
     super().initialize(ctx)
     for p in self.steps:
         if p is None:
             raise ETLConfigurationException("Component %s steps contain a None reference." % self)
         ctx.comp.initialize(p)
Esempio n. 8
0
 def initialize(self, ctx):
     if hasattr(self, '_initialized'):
         raise ETLConfigurationException(
             "Component already initialized: %s" % self)
     self._initialized = True
     self.ctx = ctx
Esempio n. 9
0
    def initialize(self, ctx):

        super(SQLTable, self).initialize(ctx)

        if self._lookup_changed_fields == None:
            self._lookup_changed_fields = []

        ctx.comp.initialize(self.connection)

        logger.debug("Loading table %s on %s" % (self.name, self))

        self.sa_metadata = MetaData()
        self.sa_table = Table(self.name, self.sa_metadata)

        self._selects = 0
        self._inserts = 0
        self._updates = 0
        self._unicode_errors = 0

        # Drop?

        columns_ex = []
        for column in self.columns:

            logger.debug("Adding column to %s: %s" % (self, column))

            column.sqltable = self

            # Check for duplicate names
            if (column.name in columns_ex):
                raise ETLConfigurationException(
                    "Duplicate column name '%s' in %s" % (column.name, self))

            columns_ex.append(column.name)

            # Configure column
            if isinstance(column, SQLColumnFK):
                if column.fk_sqlcolumn.sqltable.sa_table is None:
                    logger.warning(
                        "Column %s foreign key %s table (%s) has not been defined in backend (ignoring).",
                        column, column.fk_sqlcolumn,
                        column.fk_sqlcolumn.sqltable)
                    continue

                self.sa_table.append_column(
                    Column(column.name,
                           self._get_sa_type(column),
                           ForeignKey(
                               column.fk_sqlcolumn.sqltable.sa_table.columns[
                                   column.fk_sqlcolumn.name]),
                           primary_key=column.pk,
                           nullable=column.nullable,
                           autoincrement=(True if column.type
                                          == "AutoIncrement" else False)))
            else:
                self.sa_table.append_column(
                    Column(column.name,
                           self._get_sa_type(column),
                           primary_key=column.pk,
                           nullable=column.nullable,
                           autoincrement=(True if column.type
                                          == "AutoIncrement" else False)))

        # Check schema:

        # Create if doesn't exist
        if (not self.connection.engine().has_table(self.name)):
            logger.info("Creating table %s" % self.name)
            self.sa_table.create(self.connection.connection())
Esempio n. 10
0
    def interpolate(self, value, m=None, data=None):
        """
        Resolves expressions `${ ... }`, lambdas and functions in a value,
        with respect to the current context and the current message.

        Expressions are CubETL custom syntax for string interpolation.
        """

        # FIXME: TO BE REMOVED after migrating all interpolate calls
        if isinstance(value, dict):
            raise ETLException("Possibly invalid interpolate call!")

        if value is None:
            return None

        # If the value is a callable (function or lambda), inspect
        # its parameters. Acceptable signatures are:
        # (ctx), (m), (ctx, m)
        if callable(value):
            sig = inspect.signature(value)
            paramnames = list(sig.parameters.keys())
            if len(sig.parameters) == 1 and paramnames[0] == 'ctx':
                value = value(self)
            elif len(sig.parameters) == 1 and paramnames[0] == 'm':
                value = value(m)
            elif len(
                    sig.parameters
            ) == 2 and paramnames[0] == 'ctx' and paramnames[1] == 'm':
                value = value(self, m)
            else:
                raise ETLConfigurationException(
                    "Invalid lambda expression signature: %s" % sig)

        # If the value is not a string, it is immediately returned
        if not isinstance(value, str):
            return value

        # Process string values

        value = value.strip()

        pos = -1
        result = str(value)

        for dstart, dend in (('${|', '|}'), ('${', '}')):
            if (pos >= -1):
                pos = result.find(dstart)
            while (pos >= 0):
                pos_end = result.find(dend)
                expr = result[pos + len(dstart):pos_end].strip()

                compiled = self._compiled.get(expr)
                try:
                    if (not compiled):
                        compiled = compile(expr, '', 'eval')
                        self._compiled.put(expr, compiled)

                    c_locals = {
                        "m": m,
                        "ctx": self,
                        "f": self.f,
                        "props": self.props,
                        "var": self.var,
                        "cubetl": cubetl
                    }
                    if data:
                        c_locals.update(data)
                    res = eval(compiled, self._globals, c_locals)

                    if (self.debug2):
                        if (isinstance(res, str)):
                            logger.debug(
                                'Evaluated: %s = %r' %
                                (expr, res if
                                 (len(res) < 100) else res[:100] + ".."))
                        else:
                            logger.debug('Evaluated: %s = %r' % (expr, res))

                except (Exception) as e:
                    exc_type, exc_value, exc_traceback = sys.exc_info()

                    caller_component = None
                    frame = inspect.currentframe()
                    for caller in inspect.getouterframes(frame):
                        fc = Context._class_from_frame(caller[0])
                        if (isclass(fc) and issubclass(fc, Component)):
                            caller_component = caller[0].f_locals['self']
                            break

                    #logger.error("Error evaluating expression %s on data: %s" % (expr, m))
                    self._eval_error_message = m

                    logger.error(
                        'Error evaluating expression "%s" called from %s:\n%s'
                        % (expr, caller_component, ("".join(
                            traceback.format_exception_only(
                                exc_type, exc_value)))))
                    raise

                if (pos > 0) or (pos_end < len(result) - (len(dend))):
                    result = result[0:pos] + str(res) + result[pos_end +
                                                               (len(dend)):]
                    pos = result.find(dstart)
                else:
                    # Keep type of non-string types
                    result = res
                    pos = -2

        return result
Esempio n. 11
0
    def _get_mappings(self, ctx, mapper, base_mapper = None, parent_mapper = None):
        """
        Calculates Cubes mappings, which map Cubes entity attributes to database
        tables. This is used in the 'mappings' section of Cubes configuration.
        Returns a dictionary where keys are the mapped entity.attribute and
        values are the alias.column.
        """

        logger.debug("Exporting mappings: %s" % mapper)

        c_mappings = {}
        if (base_mapper == None):
            base_mapper = mapper

        if (isinstance(mapper, FactMapper)):
            for dim in mapper.entity.dimensions:
                dim_mapper = mapper.olapmapper.entity_mapper(dim)
                sub_mappings = self._get_mappings(ctx, dim_mapper, base_mapper, mapper)

                if isinstance(mapper.entity, AliasDimension):
                    # For AliasDimensions, the table is aliased
                    for sm in sub_mappings.items():
                        # Account for "extracted" fields, that return a dictionary:
                        if isinstance(sm[1], dict):
                            c_mappings[sm[0]] = { "column": mapper.entity.name + "." + sm[1]["column"].split(".")[1], "extract": sm[1]["extract"] }
                        else:
                            c_mappings[sm[0]] = mapper.entity.name + "." + sm[1].split(".")[1]
                else:
                    # XXX mapper.olapmapper.entity_mapper(join["detail_entity"]).entity.name
                    c_mappings.update(sub_mappings)

        elif (isinstance(mapper, MultiTableHierarchyDimensionMapper)):
            for dim in mapper.entity.levels:
                dim_mapper = self.olapmapper.entity_mapper(dim, False)
                sub_mappings = self._get_mappings(ctx, dim_mapper, base_mapper, mapper)
                for k,v in sub_mappings.items():
                    mapping_entityattribute = mapper.entity.name + "." + k.split(".")[1]
                    if mapping_entityattribute in c_mappings:
                        raise ETLConfigurationException("Attribute '%s' in %s is being mapped more than once. This can happen if the same column name is used by more than one levels in the hierarchy (hint: this happens often due to the same 'id' or 'names' attribute name being used by several dimensions in the hierarchy: use different names)." % (mapping_entityattribute, mapper))
                    c_mappings[mapping_entityattribute] = v

        elif (isinstance(mapper, EmbeddedDimensionMapper)):
            mappings = mapper._mappings_join(ctx)
            for mapping in mappings:
                if "extract" in mapping:
                    c_mappings[mapper.entity.name + "." + mapping["name"]] = {
                        "column": parent_mapper.table + "." + mapping["column"],
                        "extract": mapping["extract"]
                        }
                else:
                    c_mappings[mapper.entity.name + "." + mapping["name"]] = parent_mapper.table + "." + mapping["column"]

        elif (isinstance(mapper, DimensionMapper) or (isinstance(mapper, CompoundHierarchyDimensionMapper))):
            mappings = mapper._mappings(ctx)
            for mapping in mappings:
                c_mappings[mapper.entity.name + "." + mapping["name"]] = mapper.entity.name + "." + mapping["column"]

        else:
            raise Exception ("Unknown mapper type for cubes export: %s" % mapper)

        """
        joins = mapper._joins(ctx, None)
        mappings = mapper._mappings(ctx)

        #logger.info( mapper)
        #logger.info( mappings)
        for mapping in mappings:
            #if (mapping["entity"] == mapper.entity):
            #    c_mappings[mapping["entity"].name + "." + mapping["name"]] = mapper.table + "." + mapping["column"]
            if (mapping["entity"] not in [join["detail_entity"] for join in joins]):
                c_mappings[mapping["entity"].name + "." + mapping["name"]] = mapper.table + "." + mapping["column"]
            else:

                dim_mapper = mapper.olapmapper.entity_mapper(mapping["entity"])
                sub_mappings = self._get_mappings(ctx, dim_mapper)

                if (isinstance(dim_mapper, MultiTableHierarchyDimensionMapper)):
                    # Enforce current entity (for hierarchies, this causes that all levels are
                    # mapped for the current dimension, forcing them to have different attribute names)
                    for k,v in sub_mappings.items():
                        c_mappings[mapping["entity"].name + "." + k.split(".")[1]] = v
                else:
                    c_mappings.update(sub_mappings)
        """

        return c_mappings