Beispiel #1
0
    def test_import_from_file(self, mock_open, mock_load, mock_isfile):
        """Test process-service file import"""

        # set return values
        mock_isfile.return_value = True
        mock_file = mock.MagicMock(name='service_file')
        mock_file.__enter__.return_value = mock_file
        mock_open.return_value = mock_file

        # create mock process-service class and instance
        logger = Logger()
        ps_cls = type('ps_cls', (), {'persist': True, 'logger': logger})
        ps = mock.Mock(name='ProcessService_instance')
        ps.__class__ = ps_cls

        # test normal import
        mock_load.return_value = ps
        ps_ = ProcessService.import_from_file.__func__(ps_cls,
                                                       'mock_file_path')
        self.assertIs(ps_, ps, 'unexpected process-service instance returned')
        mock_open.assert_called_once_with('mock_file_path', 'rb')
        mock_load.assert_called_once_with(mock_file)
        mock_open.reset_mock()
        mock_load.reset_mock()

        # test importing instance of incorrect type
        mock_load.return_value = None
        with self.assertRaises(TypeError):
            ProcessService.import_from_file.__func__(ps_cls, 'mock_file_path')
        mock_open.reset_mock()
        mock_load.reset_mock()

        # test import with non-persisting service
        ps_cls.persist = False
        ps_ = ProcessService.import_from_file.__func__(ps_cls,
                                                       'mock_file_path')
        self.assertIs(ps_, None,
                      'unexpected return value for non-persisting service')
    Macro to illustrate the use of multiple chains

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject, Chain
from escore import core_ops
from escore import process_manager
from escore.logger import Logger

logger = Logger()

logger.debug('Now parsing configuration file esk102_multiple_chains')

#########################################################################################
# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk102_multiple_chains'
settings['version'] = 0

#########################################################################################
# --- Analysis values, settings, helper functions, configuration flags.

settings['do_chain0'] = True
settings['do_chain1'] = True
Beispiel #3
0
    Macro to illustrate the use of the Printdatastore link.
    Prindatastore prints an overview of the contents in the
    datastore at the state of running

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import core_ops, process_manager, ConfigObject, DataStore, Chain
from escore.logger import Logger

logger = Logger()

logger.debug('Now parsing configuration file esk103_printdatastore')

#########################################################################################
# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk103_printdatastore'
settings['version'] = 0

#########################################################################################
# --- for this macro, fill the datastore with some dummy information

process_manager.service(DataStore)['hello'] = 'world'
process_manager.service(DataStore)['d'] = {'a': 1, 'b': 2, 'c': 3}
import sys

from pytest import raises

from escore import entry_points
from escore.entry_points import eskapade_bootstrap

from escore.logger import Logger
logger = Logger()


def test_bootstrap_args():
    """Test eskapade_bootstrap arguments handling."""
    # no required arguments
    with raises(SystemExit) as excinfo:
        sys.argv[1:] = []
        eskapade_bootstrap()
        assert 'the following arguments are required' in str(excinfo.value)
    # unrecognized arguments
    with raises(SystemExit) as excinfo:
        sys.argv[1:] = ['package', 'unrecognized_arg']
        eskapade_bootstrap()
        assert 'unrecognized arguments' in str(excinfo.value)
    # use of Eskapade reserved name
    with raises(AttributeError, match='eskapade is reserved by Eskapade'):
        sys.argv[1:] = ['eskapade']
        eskapade_bootstrap()
    # use of Eskapade reserved name
    with raises(AttributeError, match='escore is reserved by Eskapade'):
        sys.argv[1:] = ['escore']
        eskapade_bootstrap()
class ProcessService(metaclass=ProcessServiceMeta):
    """Base class for process services."""

    logger = Logger()
    _persist = False

    def __init__(self):
        """Initialize service instance."""
        pass

    def __str__(self):
        """Get printable specification of service instance."""
        return '{0!s} ({1:s})'.format(type(self), hex(id(self)))

    @classmethod
    def create(cls):
        """Create an instance of this service.

        :returns: service instance
        :rtype: ProcessService
        """
        # create instance and make sure the service is initialized
        inst = cls()
        ProcessService.__init__(inst)
        return inst

    def finish(self):
        """Finish current processes.

        This function can be implemented by a process-service implementation to
        finish running processes and clean up to prepare for a reset of the
        process manager.  This would typically involve deleting large objects
        and closing files and database connections.
        """
        pass

    @classmethod
    def import_from_file(cls, file_path):
        """Import service instance from a Pickle file.

        :param str file_path: path of Pickle file
        :returns: imported service instance
        :rtype: ProcessService
        :raises: RuntimeError, TypeError
        """
        # check if service can be persisted
        if cls.persist:
            cls.logger.debug(
                'Importing service instance of "{cls!s}" from file "{path}".',
                cls=cls,
                path=file_path)
        else:
            cls.logger.debug('Not importing service "{cls!s}".', cls=cls)
            return None

        # check specified file path
        if not os.path.isfile(file_path):
            cls.logger.fatal(
                'Specified path for importing "{cls!s}" instance is not a file "{path}".',
                cls=cls,
                path=file_path)
            raise RuntimeError(
                'Invalid file path specified for importing process service.')

        try:
            # try to open file and import instance
            with open(file_path, 'rb') as inst_file:
                inst = pickle.load(inst_file)
        except Exception as exc:
            # re-raise exeption if import failed
            cls.logger.warning(
                'Failed to import service instance of "{cls!s}" from file "{path}".',
                cls=cls,
                path=file_path)
            raise exc

        # check type of instance
        if not isinstance(inst, cls):
            cls.logger.fatal(
                'Expected to import "{cls!s}" instance, got object of type "{type}".',
                cls=cls,
                type=type(inst).__name__)
            raise TypeError('Incorrect type for imported service object.')

        return inst

    def persist_in_file(self, file_path):
        """Persist service instance in Pickle file.

        :param str file_path: path of Pickle file
        """
        # check if service can be persisted
        if type(self).persist:
            self.logger.debug(
                'Persisting service instance "{instance!s}" in file "{path}".',
                instance=self,
                path=file_path)
        else:
            self.logger.debug('Not persisting service "{type!s}".',
                              type=type(self))
            return

        try:
            # try to persist
            with open(file_path, 'wb') as inst_file:
                pickle.dump(self, inst_file)
        except Exception as exc:
            # give warning if persisting failed
            self.logger.warning(
                'Failed to persist service instance "{instance!s}" in file "{path}".',
                instance=self,
                path=file_path)
            self.logger.warning('Caught exception "{exc!s}".', exc=exc)
Beispiel #6
0
    Follow-up example in macro: esk209_readdata_itr.py

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject, Chain
from escore import core_ops
from escore import process_manager
from escore.logger import Logger, LogLevel

logger = Logger()

logger.debug('Now parsing configuration file esk107_chain_looper')

#########################################################################################
# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk107_chain_looper'
settings['version'] = 0

#########################################################################################
# --- Analysis configuration flags.
#     E.g. use these flags turn on or off certain chains with links.
#     by default all set to false, unless already configured in
#     configobject or vars()
    Macro to illustrate the use of flags set from the command line.

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject, Chain
from escore import core_ops
from escore import process_manager
from escore.logger import Logger

logger = Logger()

logger.debug('Now parsing configuration file esk106_cmdline_options')

#########################################################################################
# --- minimal analysis information
settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk106_cmdline_options'
settings['version'] = 0

msg = r"""

The two flags below control whether chains are turned on or off. (default=on)
from the cmd line, control these with:

-c do_chain0=False -c do_chain1=False
    Macro illustrates how to load an external datastore from file

Authors:
    KMPG AA&BD team

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

import shutil
from escore import process_manager, Chain, ConfigObject, DataStore, core_ops
from escore.logger import Logger, LogLevel
from escore.core import persistence

logger = Logger()

logger.debug('Now parsing configuration file esk111_load_datastore_from_file.')

# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk111_load_datastore_from_file'
settings['version'] = 0

ds = process_manager.service(DataStore)
ds['number'] = 1
file_path = persistence.io_path('proc_service_data', 'temp_datastore.pkl')
ds.persist_in_file(file_path)

# --- update the number
    Macro illustrates how to persist the datastore
    and configuration object after each chain.

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject
from escore import process_manager, resources
from escore.logger import Logger

logger = Logger()

#########################################################################################
# --- Analysis values, settings, helper functions, configuration flags.

# turning on this flag, the datastore and configuration are not written out to disk
# at the end of the program.

settings = process_manager.service(ConfigObject)
settings['storeResultsEachChain'] = True

msg = r"""

The global flag settings['storeResultsEachChain'] (default = False)
controls persistence of the run-process services after the execution of
a chain.  By default, these objects are only stored after the last
Beispiel #10
0
    Macro to say hello to the world with Eskapade!

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject, Chain
from escore import core_ops
from escore import process_manager
from escore.logger import Logger, LogLevel

logger = Logger()

logger.debug('Now parsing configuration file esk101_helloworld')

#########################################################################################
# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk101_helloworld'
settings['version'] = 0

#########################################################################################
# --- Analysis values, settings, helper functions, configuration flags.

#     E.g. define flags turn on or off certain chains with links.
#     by default all set to false, unless already configured in
    Macro serves as input to other three esk105 example macros.

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject, Chain
from escore import core_ops
from escore import process_manager
from escore.logger import Logger

logger = Logger()

logger.debug('Now parsing configuration file esk105_datastore_pickling.')

#########################################################################################
# --- minimal analysis information
settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk105_datastore_pickling'
settings['version'] = 0

#########################################################################################
# --- Analysis values, settings, helper functions, configuration flags.

msg = r"""

The setup consists of three simple chains that add progressively more information to the datastore.
Beispiel #12
0
class Processor(metaclass=ABCMeta):
    """Processor metaclass."""

    logger = Logger()  # type: Logger

    def __init__(self, name: str):
        """Initialize the Processor object."""
        super().__init__()
        name = name or self.__class__.__name__
        self.__name = name  # type: str
        self.__hash = None  # type: int
        self.__parent = None

    def __str__(self) -> str:
        return self.__name

    def __repr__(self) -> str:
        return '<{klass!s} name={name!s} parent={parent!r} id={id!s}>'.format(
            klass=self.__class__.__name__,
            name=self.name,
            parent=self.__parent,
            id=id(self))

    def __eq__(self, other: 'Processor') -> bool:
        return isinstance(other, type(self)) and self.__name == other.__name

    def __hash__(self) -> int:
        if self.__hash is None:
            self.__hash = hash((type(self), self.__name))

        return self.__hash

    def _initialize(self):
        """Wrapper to call user implemented initialize."""
        self.logger.debug('Initializing link "{link!s}".', link=self)

        status = self.initialize()

        if status == StatusCode.Success:
            self.logger.debug('Successfully initialized link "{link!s}".',
                              link=self)

        return status

    @abstractmethod
    def initialize(self):
        """Initialization logic for processor."""
        raise NotImplementedError

    def _execute(self):
        """Wrapper to call user implemented execute."""
        self.logger.debug('Executing link "{link!s}".', link=self)

        status = self.execute()

        if status == StatusCode.Success:
            self.logger.debug('Successfully executed link "{link!s}".',
                              link=self)

        return status

    @abstractmethod
    def execute(self):
        """Execution logic for processor."""
        raise NotImplementedError

    def _finalize(self):
        """Wrapper to call user implemented finalize."""
        self.logger.debug('Finalizing link "{link!s}".', link=self)

        status = self.finalize()

        if status == StatusCode.Success:
            self.logger.debug('Successfully finalized link "{link!s}".',
                              link=self)

        return status

    @abstractmethod
    def finalize(self):
        """Finalization logic for processor."""
        raise NotImplementedError

    @property
    def name(self) -> str:
        """Get the name of processor.

        :return: The name of the processor.
        :rtype: str
        """
        return self.__name

    @property
    def parent(self):
        """Get the group parent.

        :return: The parent/group processor sequence.
        """
        return self.__parent

    @parent.setter
    def parent(self, the_parent) -> None:
        """Set the group parent.

        :param the_parent: The parent/group processor sequence.
        """
        self.__parent = None

        if the_parent is not None:
            # The parent will most likely outlive the processor
            # and therefore we do not want keep a strong reference
            # to the parent.
            self.__parent = proxy(the_parent)
Beispiel #13
0
Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

import datetime
import os
import sys

from escore.logger import Logger

logger = Logger(__name__)


def get_absolute_path(path):
    """Get an absolute path.

    First expands ~ if present. Second take care of any . or ..

    :param path: path
    :returns: the absolute path
    """
    return os.path.abspath(os.path.expanduser(path))


def create_file(path, file_name, content=''):
    """Create a file in a given directory.
Beispiel #14
0
Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject, Chain
from escore import DataStore
from escore import core_ops
from escore import process_manager
from escore.logger import Logger

logger = Logger()

logger.debug('Now parsing configuration file esk109_debugging_tips')

#########################################################################################
# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk109_debugging_tips'
settings['version'] = 0

#########################################################################################
# --- Analysis values, settings, helper functions, configuration flags.

msg = r"""
Beispiel #15
0
    Macro to illustrate how to control the contents of the datastore

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject, Chain
from escore import core_ops
from escore import process_manager
from escore.logger import Logger

logger = Logger()

logger.debug('Now parsing configuration file esk104_basic_datastore_operations.')

#########################################################################################
# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk104_basic_datastore_operations'
settings['version'] = 0

#########################################################################################
# --- Analysis values, settings, helper functions, configuration flags.

# some dummy information to use in this macro
f = {'hello': 'world', 'v': [3, 1, 4, 1, 5], 'n_favorite': 7}
    Macro does ...(fill in short description here)

Authors:
    Your name(s) here

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import process_manager, Chain, ConfigObject, core_ops
from escore.logger import Logger, LogLevel



logger = Logger()
logger.debug('Now parsing configuration file esk112_parallel_fork_demo.')

# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk112_parallel_fork_demo'
settings['version'] = 0

# --- now set up the chains and links

ch = Chain('Start')
ch.n_fork = 100
fe = core_ops.ForkExample()
fe.store_key = 'forkstoredemo'
fe.logger.log_level = LogLevel.DEBUG
Beispiel #17
0
Description:
    Macro to demo how to run eskapade with code profiling turned on

Authors:
    KPMG Advanced Analytics & Big Data team, Amstelveen, The Netherlands

Redistribution and use in source and binary forms, with or without
modification, are permitted according to the terms listed in the file
LICENSE.
"""

from escore import ConfigObject
from escore import process_manager
from escore.logger import Logger

logger = Logger()

logger.debug('Now parsing configuration file esk110_code_profiling.')

#########################################################################################
# --- minimal analysis information

settings = process_manager.service(ConfigObject)
settings['analysisName'] = 'esk110_code_profiling'
settings['version'] = 0

#########################################################################################
# --- Analysis values, settings, helper functions, configuration flags.

msg = r"""