<commit_before>import numpy as np
import scipy as sp
import tables as tb
import sys
import os

from pyne import data
from pyne import nucname
from pyne import nuc_data
from pyne.material import Material
from pyne.xs.data_source import EAF_RX

def decay(nuc, phi, t_sim, tol):
    """Decays a material into its daughters.

    Parameters
    ----------
    nuc : nucname
        Name of the nuclide in decay.
    phi : NumPy array of floats
        Neutron flux vector of length 175.
    t_sim : float
        Time to decay for.
    tol : float
        Tolerance level for chain truncation.

    Returns
    -------
    decay_nuc : NumPy array of nucnames
        The daughters.
    """
    # Check parameters
    # Convert nuc to zzaaam
    nuc = nucname.zzaaam(nuc)
    # Check length of phi
    if not(phi.size == 175):
        sys.exit('Incorrect phi dimension for FENDL data.')
    A = _create_decay_matrix(nuc)
    eA = _solve_decay_matrix(A)
    data_table.close()

def _create_decay_matrix(nucs):
    """Creates a NumPy matrix representing the nuclide list nucs.

    Parameters
    ----------
    nucs : NumPy array of nucnames
        Names of nuclides to build decay matrix around.

    Returns
    -------
    A : NumPy matrix of floats
        The decay matrix.
    """
    nnucs = len(nucs)
    nucsrange = np.arange(nnucs)
    A = np.zeros((nnucs, nnucs), dtype=float)
    A[nucsrange, nucsrange] = [-data.decay_const(nuc) for nuc in nucs]
    return A

def _solve_decay_matrix(A):
    eA = sp.linalg.expm(A)
    return eA

def _get_daughters(nuc):
    """Returns a dictionary that contains the neutron-reaction daughters of
    nuc as keys to the 175-group neutron cross sections for that daughter's
    reaction.

    Parameters
    ----------
    nuc : nucname
        Name of parent nuclide to get daughters of.

    Returns
    -------
    daugh_dict : dictionary
        Keys are the neutron-reaction daughters of nuc in zzaaam format.
        Values are a NumPy array containing the EAF cross section data.
            (all Values should have size 175)
    """
    daugh_dict = {}
    # Remove fission MT# (cannot handle)
    if '180' in EAF_RX:
        EAF_RX.remove('180')
    # Open nuc_data.h5
    with tb.openFile(nuc_data, 'r') as f:
        # Set working node that contains EAF cross sections
        node = f.root.neutron.eaf_xs.eaf_xs
        cond = "(nuc_zz == {0})".format(nuc)
        daughters = [row['daughter'] for row in node.where(cond)]
        all_xs = [np.array(row['xs']) for row in node.where(cond)]
        all_rx = [row['rxnum'] for row in node.where(cond)]
    for i in range(len(daughters)):
        if all_rx[i] not in EAF_RX:
            continue
        daugh = _convert_eaf(daughters[i])
        xs = all_xs[i]
        daugh_dict[daugh] = xs
    return daugh_dict

def _convert_eaf(daugh):
    """Returns the zzaaam format of a daugh string in parsed EAF format.

    Parameters
    ----------
    daugh : String
        String representation of a daughter in EAF format.

    Returns
    -------
    daugh_conv : nucname
        Name of daugh in zzaaam format appropriate for PyNE.
    """
    # Remove possible space from string
    daugh = daugh.replace(' ', '')
    # Check for 'G' suffix
    daugh = daugh.replace('G', '')
    # Check for metastable suffix
    if daugh.endswith('M1') or daugh.endswith('M2'):
        # Convert appropriately
        parts = daugh.rsplit('M',1)
        daugh_conv = nucname.zzaaam(parts[0]) + int(parts[1])
    else:
        daugh_conv = nucname.zzaaam(daugh)
    return daugh_conv

def _get_decay(nuc):
    """Returns a dictionary that contains the decay children of nuc as keys
    to the branch ratio of that child's decay process.

    Parameters
    ----------
    nuc : nucname
        Name of parent nuclide to get decay children of.

    Returns
    -------
    decay_dict : dictionary
        Keys are decay children of nuc in zzaaam format.
        Values are the branch ratio of the decay child.
    """
    decay_dict = {}
    nuc = nucname.zzaaam(nuc)
    children = data.decay_children(nuc)
    for child in children:
        branch = data.branch_ratio(nuc,child)
        decay_dict[child] = branch
    return decay_dict
<commit_msg>Added _get_destruction method. The calculation of the total cross section is likely incorrect.<commit_after>import numpy as np
import scipy as sp
import tables as tb
import sys
import os

from pyne import data
from pyne import nucname
from pyne import nuc_data
from pyne.material import Material
from pyne.xs.data_source import EAF_RX

def decay(nuc, phi, t_sim, tol):
    """Decays a material into its daughters.

    Parameters
    ----------
    nuc : nucname
        Name of the nuclide in decay.
    phi : NumPy array of floats
        Neutron flux vector of length 175.
    t_sim : float
        Time to decay for.
    tol : float
        Tolerance level for chain truncation.

    Returns
    -------
    decay_nuc : NumPy array of nucnames
        The daughters.
    """
    # Check parameters
    # Convert nuc to zzaaam
    nuc = nucname.zzaaam(nuc)
    # Check length of phi
    if not(phi.size == 175):
        sys.exit('Incorrect phi dimension for FENDL data.')
    A = _create_decay_matrix(nuc)
    eA = _solve_decay_matrix(A)
    data_table.close()

def _create_decay_matrix(nucs):
    """Creates a NumPy matrix representing the nuclide list nucs.

    Parameters
    ----------
    nucs : NumPy array of nucnames
        Names of nuclides to build decay matrix around.

    Returns
    -------
    A : NumPy matrix of floats
        The decay matrix.
    """
    nnucs = len(nucs)
    nucsrange = np.arange(nnucs)
    A = np.zeros((nnucs, nnucs), dtype=float)
    A[nucsrange, nucsrange] = [-data.decay_const(nuc) for nuc in nucs]
    return A

def _solve_decay_matrix(A):
    eA = sp.linalg.expm(A)
    return eA

def _get_daughters(nuc):
    """Returns a dictionary that contains the neutron-reaction daughters of
    nuc as keys to the 175-group neutron cross sections for that daughter's
    reaction.

    Parameters
    ----------
    nuc : nucname
        Name of parent nuclide to get daughters of.

    Returns
    -------
    daugh_dict : dictionary
        Keys are the neutron-reaction daughters of nuc in zzaaam format.
        Values are a NumPy array containing the EAF cross section data.
            (all Values should have size 175)
    """
    daugh_dict = {}
    # Remove fission MT# (cannot handle)
    if '180' in EAF_RX:
        EAF_RX.remove('180')
    # Open nuc_data.h5
    with tb.openFile(nuc_data, 'r') as f:
        # Set working node that contains EAF cross sections
        node = f.root.neutron.eaf_xs.eaf_xs
        cond = "(nuc_zz == {0})".format(nuc)
        daughters = [row['daughter'] for row in node.where(cond)]
        all_xs = [np.array(row['xs']) for row in node.where(cond)]
        all_rx = [row['rxnum'] for row in node.where(cond)]
    for i in range(len(daughters)):
        if all_rx[i] not in EAF_RX:
            continue
        daugh = _convert_eaf(daughters[i])
        xs = all_xs[i]
        daugh_dict[daugh] = xs
    return daugh_dict

def _convert_eaf(daugh):
    """Returns the zzaaam format of a daugh string in parsed EAF format.

    Parameters
    ----------
    daugh : String
        String representation of a daughter in EAF format.

    Returns
    -------
    daugh_conv : nucname
        Name of daugh in zzaaam format appropriate for PyNE.
    """
    # Remove possible space from string
    daugh = daugh.replace(' ', '')
    # Check for 'G' suffix
    daugh = daugh.replace('G', '')
    # Check for metastable suffix
    if daugh.endswith('M1') or daugh.endswith('M2'):
        # Convert appropriately
        parts = daugh.rsplit('M',1)
        daugh_conv = nucname.zzaaam(parts[0]) + int(parts[1])
    else:
        daugh_conv = nucname.zzaaam(daugh)
    return daugh_conv

def _get_decay(nuc):
    """Returns a dictionary that contains the decay children of nuc as keys
    to the branch ratio of that child's decay process.

    Parameters
    ----------
    nuc : nucname
        Name of parent nuclide to get decay children of.

    Returns
    -------
    decay_dict : dictionary
        Keys are decay children of nuc in zzaaam format.
        Values are the branch ratio of the decay child.
    """
    decay_dict = {}
    nuc = nucname.zzaaam(nuc)
    children = data.decay_children(nuc)
    for child in children:
        branch = data.branch_ratio(nuc,child)
        decay_dict[child] = branch
    return decay_dict

def _get_destruction(nuc, phi, rxn_dict = None)
    """Returns the destruction rate of the nuclide.

    Parameters
    ----------
    nuc : nucname
        Name of the nuclide in question

    rxn_dict : dictionary
        Contains the dictionary of neutron reactions for nuc that follows the
        structure of _get_daughters() output. This variable avoids a second
        lookup of the information if the user has already called
        _get_daughters().

    Returns
    -------
    d : float
        Destruction rate of the nuclide.
    """
    nuc = nucname.zzaaam(nuc)
    if rxn_dict is None:
        rxn_dict = _get_daughters(nuc)
    xs_total = np.zeros((175))
    for nuc in rxn_dict.keys():
        xs_total = xs_total + rxn_dict[nuc]
    decay_const = data.decay_const(nuc)
    d = decay_const + sum(xs_total*phi)
    return d

<|endoftext|>


<commit_before>#!/usr/bin/env python

"""Events framework with publisher, subscriber and repository."""

__author__ = 'Dave Foster <dfoster@asascience.com>, Michael Meisinger'
__license__ = 'Apache 2.0'

import functools
import sys
import traceback
from gevent import event as gevent_event

from pyon.core import bootstrap
from pyon.core.exception import BadRequest, IonException, StreamException
from pyon.datastore.datastore import DataStore
from pyon.ion.identifier import create_unique_event_id
from pyon.net.endpoint import Publisher, Subscriber
from pyon.util.async import spawn
from pyon.util.containers import get_ion_ts, is_valid_ts
from pyon.util.log import log

from interface.objects import Event

# @TODO: configurable
EVENTS_XP = "pyon.events"
EVENTS_XP_TYPE = "topic"

PERSIST_ON_PUBLISH = False

#The event will be ignored if older than this time period
VALID_EVENT_TIME_PERIOD = 365 * 24 * 60 * 60 * 1000   # one year

def get_events_exchange_point():
    return "%s.%s" % (bootstrap.get_sys_name(), EVENTS_XP)

class EventError(IonException):
    status_code = 500

class EventPublisher(Publisher):

    def __init__(self, event_type=None, xp=None, **kwargs):
        """
        Constructs a publisher of events for a specific type.

        @param  event_type  The name of the event type object
        @param  xp          Exchange (AMQP) name, can be none, will use events default.
        """

        self.event_type = event_type

        if bootstrap.container_instance and getattr(bootstrap.container_instance, 'event_repository', None):
            self.event_repo = bootstrap.container_instance.event_repository
        else:
            self.event_repo = None

        # generate an exchange name to publish events to
        xp = xp or get_events_exchange_point()
        name = (xp, None)

        Publisher.__init__(self, to_name=name, **kwargs)

    def _topic(self, event_object):
        """
        Builds the topic that this event should be published to.
        """
        assert event_object
        base_types = event_object.base_types or []
        base_str = ".".join(reversed(base_types))
        sub_type = event_object.sub_type or "_"
        origin_type = event_object.origin_type or "_"
        routing_key = "%s.%s.%s.%s.%s" % (base_str, event_object._get_type(), sub_type, origin_type, event_object.origin)
        return routing_key

    def publish_event_object(self, event_object):
        """
        Publishes an event of given type for the given origin. Event_type defaults to an
        event_type set when initializing the EventPublisher. Other kwargs fill out the fields
        of the event. This operation will fail with an exception.
        @param event_object     the event object to be published
        @retval event_object    the event object which was published
        """
        assert event_object

        topic = self._topic(event_object)
        to_name = (self._send_name.exchange, topic)
        log.trace("Publishing event message to %s", to_name)

        current_time = int(get_ion_ts())

        #Ensure valid created timestamp if supplied
        if event_object.ts_created:

            if not is_valid_ts(event_object.ts_created):
                raise BadRequest("The ts_created value is not a valid timestamp: '%s'" % (event_object.ts_created))

            #Reject events that are older than specified time
            if int(event_object.ts_created) > ( current_time + VALID_EVENT_TIME_PERIOD ):
                raise BadRequest("This ts_created value is too far in the future:'%s'" % (event_object.ts_created))

            #Reject events that are older than specified time
            if int(event_object.ts_created) < (current_time - VALID_EVENT_TIME_PERIOD) :
                raise BadRequest("This ts_created value is too old:'%s'" % (event_object.ts_created))

        else:
            event_object.ts_created = str(current_time)

        #Validate this object
        #TODO - enable this once the resource agent issue sending a dict is figured out
        #event_object._validate()

        #Ensure the event object has a unique id
        if '_id' in event_object:
            raise BadRequest("The event object cannot contain a _id field '%s'" % (event_object))

        #Generate a unique ID for this event
        event_object._id = create_unique_event_id()

        try:
            self.publish(event_object, to_name=to_name)
        except Exception as ex:
            log.exception("Failed to publish event (%s): '%s'" % (ex.message, event_object))
            raise

        try:
            # store published event but only if we specified an event_repo
            if PERSIST_ON_PUBLISH and self.event_repo:
                self.event_repo.put_event(event_object)
        except Exception as ex:
            log.exception("Failed to store published event (%s): '%s'" % (ex.message, event_object))
            raise

        return event_object

    def publish_event(self, origin=None, event_type=None, **kwargs):
        """
        Publishes an event of given type for the given origin. Event_type defaults to an
        event_type set when initializing the EventPublisher. Other kwargs fill out the fields
        of the event. This operation will fail with an exception.
        @param origin     the origin field value
        @param event_type the event type (defaults to the EventPublisher's event_type if set)
        @param kwargs     additional event fields
        @retval event_object    the event object which was published
        """

        event_type = event_type or self.event_type
        assert event_type

        event_object = bootstrap.IonObject(event_type, origin=origin, **kwargs)
        event_object.base_types = event_object._get_extends()
        ret_val = self.publish_event_object(event_object)
        return ret_val

class BaseEventSubscriberMixin(object):
    """
    A mixin class for Event subscribers to facilitate inheritance.

    EventSubscribers must come in both standard and process level versions, which
    rely on common base code. It is difficult to multiple inherit due to both of
    them sharing a base class, so this mixin is preferred.
    """

    @staticmethod
    def _topic(event_type, origin, sub_type=None, origin_type=None):
        """
        Builds the topic that this event should be published to.
        If either side of the event_id.origin pair are missing, will subscribe to anything.
        """
        if event_type == "Event":
            event_type = "Event.#"
        elif event_type:
            event_type = "#.%s.#" % event_type
        else:
            event_type = "#"

        sub_type = sub_type or "*.#"
        origin_type = origin_type or "*"
        origin      = origin or "*"

        return "%s.%s.%s.%s" % (event_type, sub_type, origin_type, origin)

    def __init__(self, xp_name=None, event_type=None, origin=None, queue_name=None,
                 sub_type=None, origin_type=None, pattern=None):
        self.event_type = event_type
        self.sub_type = sub_type
        self.origin_type = origin_type
        self.origin = origin

        xp_name = xp_name or get_events_exchange_point()
        if pattern:
            binding = pattern
        else:
            binding = self._topic(event_type, origin, sub_type, origin_type)
        self.binding = binding

        # TODO: Provide a case where we can have multiple bindings (e.g. different event_types)

        # prefix the queue_name, if specified, with the sysname
        # this is because queue names transcend xp boundaries (see R1 OOIION-477)
        if queue_name is not None:
            if not queue_name.startswith(bootstrap.get_sys_name()):
                queue_name = "%s.%s" % (bootstrap.get_sys_name(), queue_name)
                log.warn("queue_name specified, prepending sys_name to it: %s", queue_name)

        # set this name to be picked up by inherited folks
        self._ev_recv_name = (xp_name, queue_name)

class EventSubscriber(Subscriber, BaseEventSubscriberMixin):

    ALL_EVENTS = "#"

    def __init__(self, xp_name=None, event_type=None, origin=None, queue_name=None, callback=None,
                 sub_type=None, origin_type=None, pattern=None, auto_delete=None, *args, **kwargs):
        """
        Initializer.

        If the queue_name is specified here, the sysname is prefixed automatically to it. This is because
        named queues are not namespaces to their exchanges, so two different systems on the same broker
        can cross-pollute messages if a named queue is used.

        Note: an EventSubscriber needs to be closed to free broker resources
        """
        self._cbthread = None
        self._auto_delete = auto_delete

        BaseEventSubscriberMixin.__init__(self, xp_name=xp_name, event_type=event_type, origin=origin,
                                          queue_name=queue_name, sub_type=sub_type, origin_type=origin_type, pattern=pattern)

        log.debug("EventPublisher events pattern %s", self.binding)

        Subscriber.__init__(self, from_name=self._ev_recv_name, binding=self.binding, callback=callback, **kwargs)

    def start(self):
        """
        Pass in a subscriber here, this will make it listen in a background greenlet.
        """
        assert not self._cbthread, "start called twice on EventSubscriber"
        gl = spawn(self.listen)
        self._cbthread = gl
        if not self._ready_event.wait(timeout=5):
            log.warning('EventSubscriber start timed out.')
        log.info("EventSubscriber started. Event pattern=%s" % self.binding)
        return gl

    def stop(self):
        self.close()
        self._cbthread.join(timeout=5)
        self._cbthread.kill()
        self._cbthread = None
        log.info("EventSubscriber stopped. Event pattern=%s" % self.binding)

    def __str__(self):
        return "EventSubscriber at %s:\n\trecv_name: %s\n\tcb: %s" % (hex(id(self)), str(self._recv_name), str(self._callback))

    def _create_channel(self, **kwargs):
        """
        Override to set the channel's queue_auto_delete property.
        """
        ch = Subscriber._create_channel(self, **kwargs)
        if self._auto_delete is not None:
            ch.queue_auto_delete = self._auto_delete

        return ch

class EventRepository(object):
    """
    Class that uses a data store to provide a persistent repository for ION events.
    """

    def __init__(self, datastore_manager=None, container=None):
        self.container = container or bootstrap.container_instance

        # Get an instance of datastore configured as directory.
        # May be persistent or mock, forced clean, with indexes
        datastore_manager = datastore_manager or self.container.datastore_manager
        self.event_store = datastore_manager.get_datastore("events", DataStore.DS_PROFILE.EVENTS)

    def start(self):
        pass

    def stop(self):
        self.close()

    def close(self):
        """
        Pass-through method to close the underlying datastore.
        """
        self.event_store.close()

    def put_event(self, event):
        log.trace("Store event persistently %s", event)
        if not isinstance(event, Event):
            raise BadRequest("event must be type Event, not %s" % type(event))
        return self.event_store.create(event)

    def put_events(self, events):
        log.debug("Store %s events persistently", len(events))
        if type(events) is not list:
            raise BadRequest("events must be type list, not %s" % type(events))
        if not all([isinstance(event, Event) for event in events]):
            raise BadRequest("events must all be type Event")

        if events:
            return self.event_store.create_mult(events, allow_ids=True)
        else:
            return None

    def get_event(self, event_id):
        log.trace("Retrieving persistent event for id=%s", event_id)
        event_obj = self.event_store.read(event_id)
        return event_obj

    def find_events(self, event_type=None, origin=None, start_ts=None, end_ts=None, **kwargs):
        log.trace("Retrieving persistent event for event_type=%s, origin=%s, start_ts=%s, end_ts=%s, descending=%s, limit=%s",
                  event_type,origin,start_ts,end_ts,kwargs.get("descending", None),kwargs.get("limit",None))
        events = None

        design_name = "event"
        view_name = None
        start_key = []
        end_key = []
        if origin and event_type:
            view_name = "by_origintype"
            start_key = [origin, event_type]
            end_key = [origin, event_type]
        elif origin:
            view_name = "by_origin"
            start_key = [origin]
            end_key = [origin]
        elif event_type:
            view_name = "by_type"
            start_key = [event_type]
            end_key = [event_type]
        elif start_ts or end_ts:
            view_name = "by_time"
            start_key = []
            end_key = []
        else:
            view_name = "by_time"
            if kwargs.get("limit", 0) < 1:
                kwargs["limit"] = 100
                log.warn("Querying all events, no limit given. Set limit to 100")

        if start_ts:
            start_key.append(start_ts)
        if end_ts:
            end_key.append(end_ts)

        events = self.event_store.find_by_view(design_name, view_name, start_key=start_key, end_key=end_key,
                                               id_only=False, **kwargs)

        return events

class EventGate(EventSubscriber):
    def __init__(self, *args, **kwargs):
        EventSubscriber.__init__(self, *args, callback=self.trigger_cb, **kwargs)

    def trigger_cb(self, event):
        self.stop()
        self.gate.set()

    def await(self, timeout=None):
        self.gate = gevent_event.Event()
        self.start()
        return self.gate.wait(timeout)

    def check_or_await(self):
        pass

def handle_stream_exception(iorigin="stream_exception"):
    """
    decorator for stream exceptions
    """
    def real_decorator(fn):
        @functools.wraps(fn)
        def wrapped(*args, **kwargs):
            try:
                fn(*args, **kwargs)
            except StreamException as e:
                info = "".join(traceback.format_tb(sys.exc_info()[2]))
                pub = EventPublisher(event_type="ExceptionEvent")
                pub.publish_event(origin=iorigin, description="stream exception event", exception_type=str(type(e)), message=info)
        return wrapped
    return real_decorator

<commit_msg>Removed event persist on publish option<commit_after>#!/usr/bin/env python

"""Events framework with publisher, subscriber and repository."""

__author__ = 'Dave Foster <dfoster@asascience.com>, Michael Meisinger'
__license__ = 'Apache 2.0'

import functools
import sys
import traceback
from gevent import event as gevent_event

from pyon.core import bootstrap
from pyon.core.exception import BadRequest, IonException, StreamException
from pyon.datastore.datastore import DataStore
from pyon.ion.identifier import create_unique_event_id
from pyon.net.endpoint import Publisher, Subscriber
from pyon.util.async import spawn
from pyon.util.containers import get_ion_ts, is_valid_ts
from pyon.util.log import log

from interface.objects import Event

# @TODO: configurable
EVENTS_XP = "pyon.events"
EVENTS_XP_TYPE = "topic"

#The event will be ignored if older than this time period
VALID_EVENT_TIME_PERIOD = 365 * 24 * 60 * 60 * 1000   # one year

def get_events_exchange_point():
    return "%s.%s" % (bootstrap.get_sys_name(), EVENTS_XP)

class EventError(IonException):
    status_code = 500

class EventPublisher(Publisher):

    def __init__(self, event_type=None, xp=None, **kwargs):
        """
        Constructs a publisher of events for a specific type.

        @param  event_type  The name of the event type object
        @param  xp          Exchange (AMQP) name, can be none, will use events default.
        """

        self.event_type = event_type

        if bootstrap.container_instance and getattr(bootstrap.container_instance, 'event_repository', None):
            self.event_repo = bootstrap.container_instance.event_repository
        else:
            self.event_repo = None

        # generate an exchange name to publish events to
        xp = xp or get_events_exchange_point()
        name = (xp, None)

        Publisher.__init__(self, to_name=name, **kwargs)

    def _topic(self, event_object):
        """
        Builds the topic that this event should be published to.
        """
        assert event_object
        base_types = event_object.base_types or []
        base_str = ".".join(reversed(base_types))
        sub_type = event_object.sub_type or "_"
        origin_type = event_object.origin_type or "_"
        routing_key = "%s.%s.%s.%s.%s" % (base_str, event_object._get_type(), sub_type, origin_type, event_object.origin)
        return routing_key

    def publish_event_object(self, event_object):
        """
        Publishes an event of given type for the given origin. Event_type defaults to an
        event_type set when initializing the EventPublisher. Other kwargs fill out the fields
        of the event. This operation will fail with an exception.
        @param event_object     the event object to be published
        @retval event_object    the event object which was published
        """
        assert event_object

        topic = self._topic(event_object)
        to_name = (self._send_name.exchange, topic)
        log.trace("Publishing event message to %s", to_name)

        current_time = int(get_ion_ts())

        #Ensure valid created timestamp if supplied
        if event_object.ts_created:

            if not is_valid_ts(event_object.ts_created):
                raise BadRequest("The ts_created value is not a valid timestamp: '%s'" % (event_object.ts_created))

            #Reject events that are older than specified time
            if int(event_object.ts_created) > ( current_time + VALID_EVENT_TIME_PERIOD ):
                raise BadRequest("This ts_created value is too far in the future:'%s'" % (event_object.ts_created))

            #Reject events that are older than specified time
            if int(event_object.ts_created) < (current_time - VALID_EVENT_TIME_PERIOD) :
                raise BadRequest("This ts_created value is too old:'%s'" % (event_object.ts_created))

        else:
            event_object.ts_created = str(current_time)

        #Validate this object
        #TODO - enable this once the resource agent issue sending a dict is figured out
        #event_object._validate()

        #Ensure the event object has a unique id
        if '_id' in event_object:
            raise BadRequest("The event object cannot contain a _id field '%s'" % (event_object))

        #Generate a unique ID for this event
        event_object._id = create_unique_event_id()

        try:
            self.publish(event_object, to_name=to_name)
        except Exception as ex:
            log.exception("Failed to publish event (%s): '%s'" % (ex.message, event_object))
            raise

        return event_object

    def publish_event(self, origin=None, event_type=None, **kwargs):
        """
        Publishes an event of given type for the given origin. Event_type defaults to an
        event_type set when initializing the EventPublisher. Other kwargs fill out the fields
        of the event. This operation will fail with an exception.
        @param origin     the origin field value
        @param event_type the event type (defaults to the EventPublisher's event_type if set)
        @param kwargs     additional event fields
        @retval event_object    the event object which was published
        """

        event_type = event_type or self.event_type
        assert event_type

        event_object = bootstrap.IonObject(event_type, origin=origin, **kwargs)
        event_object.base_types = event_object._get_extends()
        ret_val = self.publish_event_object(event_object)
        return ret_val

class BaseEventSubscriberMixin(object):
    """
    A mixin class for Event subscribers to facilitate inheritance.

    EventSubscribers must come in both standard and process level versions, which
    rely on common base code. It is difficult to multiple inherit due to both of
    them sharing a base class, so this mixin is preferred.
    """

    @staticmethod
    def _topic(event_type, origin, sub_type=None, origin_type=None):
        """
        Builds the topic that this event should be published to.
        If either side of the event_id.origin pair are missing, will subscribe to anything.
        """
        if event_type == "Event":
            event_type = "Event.#"
        elif event_type:
            event_type = "#.%s.#" % event_type
        else:
            event_type = "#"

        sub_type = sub_type or "*.#"
        origin_type = origin_type or "*"
        origin      = origin or "*"

        return "%s.%s.%s.%s" % (event_type, sub_type, origin_type, origin)

    def __init__(self, xp_name=None, event_type=None, origin=None, queue_name=None,
                 sub_type=None, origin_type=None, pattern=None):
        self.event_type = event_type
        self.sub_type = sub_type
        self.origin_type = origin_type
        self.origin = origin

        xp_name = xp_name or get_events_exchange_point()
        if pattern:
            binding = pattern
        else:
            binding = self._topic(event_type, origin, sub_type, origin_type)
        self.binding = binding

        # TODO: Provide a case where we can have multiple bindings (e.g. different event_types)

        # prefix the queue_name, if specified, with the sysname
        # this is because queue names transcend xp boundaries (see R1 OOIION-477)
        if queue_name is not None:
            if not queue_name.startswith(bootstrap.get_sys_name()):
                queue_name = "%s.%s" % (bootstrap.get_sys_name(), queue_name)
                log.warn("queue_name specified, prepending sys_name to it: %s", queue_name)

        # set this name to be picked up by inherited folks
        self._ev_recv_name = (xp_name, queue_name)

class EventSubscriber(Subscriber, BaseEventSubscriberMixin):

    ALL_EVENTS = "#"

    def __init__(self, xp_name=None, event_type=None, origin=None, queue_name=None, callback=None,
                 sub_type=None, origin_type=None, pattern=None, auto_delete=None, *args, **kwargs):
        """
        Initializer.

        If the queue_name is specified here, the sysname is prefixed automatically to it. This is because
        named queues are not namespaces to their exchanges, so two different systems on the same broker
        can cross-pollute messages if a named queue is used.

        Note: an EventSubscriber needs to be closed to free broker resources
        """
        self._cbthread = None
        self._auto_delete = auto_delete

        BaseEventSubscriberMixin.__init__(self, xp_name=xp_name, event_type=event_type, origin=origin,
                                          queue_name=queue_name, sub_type=sub_type, origin_type=origin_type, pattern=pattern)

        log.debug("EventPublisher events pattern %s", self.binding)

        Subscriber.__init__(self, from_name=self._ev_recv_name, binding=self.binding, callback=callback, **kwargs)

    def start(self):
        """
        Pass in a subscriber here, this will make it listen in a background greenlet.
        """
        assert not self._cbthread, "start called twice on EventSubscriber"
        gl = spawn(self.listen)
        self._cbthread = gl
        if not self._ready_event.wait(timeout=5):
            log.warning('EventSubscriber start timed out.')
        log.info("EventSubscriber started. Event pattern=%s" % self.binding)
        return gl

    def stop(self):
        self.close()
        self._cbthread.join(timeout=5)
        self._cbthread.kill()
        self._cbthread = None
        log.info("EventSubscriber stopped. Event pattern=%s" % self.binding)

    def __str__(self):
        return "EventSubscriber at %s:\n\trecv_name: %s\n\tcb: %s" % (hex(id(self)), str(self._recv_name), str(self._callback))

    def _create_channel(self, **kwargs):
        """
        Override to set the channel's queue_auto_delete property.
        """
        ch = Subscriber._create_channel(self, **kwargs)
        if self._auto_delete is not None:
            ch.queue_auto_delete = self._auto_delete

        return ch

class EventRepository(object):
    """
    Class that uses a data store to provide a persistent repository for ION events.
    """

    def __init__(self, datastore_manager=None, container=None):
        self.container = container or bootstrap.container_instance

        # Get an instance of datastore configured as directory.
        # May be persistent or mock, forced clean, with indexes
        datastore_manager = datastore_manager or self.container.datastore_manager
        self.event_store = datastore_manager.get_datastore("events", DataStore.DS_PROFILE.EVENTS)

    def start(self):
        pass

    def stop(self):
        self.close()

    def close(self):
        """
        Pass-through method to close the underlying datastore.
        """
        self.event_store.close()

    def put_event(self, event):
        log.trace("Store event persistently %s", event)
        if not isinstance(event, Event):
            raise BadRequest("event must be type Event, not %s" % type(event))
        return self.event_store.create(event)

    def put_events(self, events):
        log.debug("Store %s events persistently", len(events))
        if type(events) is not list:
            raise BadRequest("events must be type list, not %s" % type(events))
        if not all([isinstance(event, Event) for event in events]):
            raise BadRequest("events must all be type Event")

        if events:
            return self.event_store.create_mult(events, allow_ids=True)
        else:
            return None

    def get_event(self, event_id):
        log.trace("Retrieving persistent event for id=%s", event_id)
        event_obj = self.event_store.read(event_id)
        return event_obj

    def find_events(self, event_type=None, origin=None, start_ts=None, end_ts=None, **kwargs):
        log.trace("Retrieving persistent event for event_type=%s, origin=%s, start_ts=%s, end_ts=%s, descending=%s, limit=%s",
                  event_type,origin,start_ts,end_ts,kwargs.get("descending", None),kwargs.get("limit",None))
        events = None

        design_name = "event"
        view_name = None
        start_key = []
        end_key = []
        if origin and event_type:
            view_name = "by_origintype"
            start_key = [origin, event_type]
            end_key = [origin, event_type]
        elif origin:
            view_name = "by_origin"
            start_key = [origin]
            end_key = [origin]
        elif event_type:
            view_name = "by_type"
            start_key = [event_type]
            end_key = [event_type]
        elif start_ts or end_ts:
            view_name = "by_time"
            start_key = []
            end_key = []
        else:
            view_name = "by_time"
            if kwargs.get("limit", 0) < 1:
                kwargs["limit"] = 100
                log.warn("Querying all events, no limit given. Set limit to 100")

        if start_ts:
            start_key.append(start_ts)
        if end_ts:
            end_key.append(end_ts)

        events = self.event_store.find_by_view(design_name, view_name, start_key=start_key, end_key=end_key,
                                               id_only=False, **kwargs)

        return events

class EventGate(EventSubscriber):
    def __init__(self, *args, **kwargs):
        EventSubscriber.__init__(self, *args, callback=self.trigger_cb, **kwargs)

    def trigger_cb(self, event):
        self.stop()
        self.gate.set()

    def await(self, timeout=None):
        self.gate = gevent_event.Event()
        self.start()
        return self.gate.wait(timeout)

    def check_or_await(self):
        pass

def handle_stream_exception(iorigin="stream_exception"):
    """
    decorator for stream exceptions
    """
    def real_decorator(fn):
        @functools.wraps(fn)
        def wrapped(*args, **kwargs):
            try:
                fn(*args, **kwargs)
            except StreamException as e:
                info = "".join(traceback.format_tb(sys.exc_info()[2]))
                pub = EventPublisher(event_type="ExceptionEvent")
                pub.publish_event(origin=iorigin, description="stream exception event", exception_type=str(type(e)), message=info)
        return wrapped
    return real_decorator

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

'''Opus decoder.'''

from __future__ import unicode_literals, absolute_import

__all__ = [
        'OpusDecoder',
        ]

from . import base
from . import llinterface
from . import utils

class OpusDecoder(base.OpusCodec):
    '''Opus decoder.'''

    def __init__(self, frequency, channels):
        # basic sanity check
        utils.check_freq(frequency)
        utils.check_channels(channels)

        self.frequency = frequency
        self.channels = channels

        # initialize state
        super(OpusDecoder, self).__init__()

    def _get_state_size(self):
        return llinterface.decoder_get_size(self.channels)

    def _init_state(self):
        llinterface.decoder_init(self._state, self.frequency, self.channels)

# vim:set ai et ts=4 sw=4 sts=4 fenc=utf-8:
<commit_msg>implement CTL interface on OpusDecoder<commit_after># -*- coding: utf-8 -*-

'''Opus decoder.'''

from __future__ import unicode_literals, absolute_import

__all__ = [
        'OpusDecoder',
        ]

from . import base
from . import llinterface
from . import ctl
from . import utils

class OpusDecoder(base.OpusCodec):
    '''Opus decoder.'''

    def __init__(self, frequency, channels):
        # basic sanity check
        utils.check_freq(frequency)
        utils.check_channels(channels)

        self.frequency = frequency
        self.channels = channels

        # initialize state
        super(OpusDecoder, self).__init__()

    def _get_state_size(self):
        return llinterface.decoder_get_size(self.channels)

    def _init_state(self):
        llinterface.decoder_init(self._state, self.frequency, self.channels)

    def reset_state(self):
        ctl.decoder_reset_state(self._state)

    @property
    def final_range(self):
        return ctl.decoder_get_final_range(self._state)

    @property
    def pitch(self):
        return ctl.decoder_get_pitch(self._state)

    @property
    def bandwidth(self):
        return ctl.decoder_get_bandwidth(self._state)

    @property
    def gain(self):
        return ctl.decoder_get_gain(self._state)

    @gain.setter
    def gain(self, value):
        ctl.decoder_set_gain(self._state, value)

# vim:set ai et ts=4 sw=4 sts=4 fenc=utf-8:
<|endoftext|>


<commit_before>from pyquery import PyQuery
import time

## Filters a PyQuery object populated from a Wiki page for links
# @param    selector    An optional DOM selector for elements containing desired links
# @return               A list of link URLs
def filter_links(page, selector=""):
    result = []
    subchildren = PyQuery(page("#mw-content-text " + selector))
    for child in subchildren:
        links = PyQuery(child)("a")
        for link in links:
            linkQuery = PyQuery(link)
            if not linkQuery.hasClass("mw-redirect"):
                href = linkQuery.attr("href")
                if "/wiki/" in href and "#" not in href:
                    result.append(linkQuery.attr("href"))
    return result

## Retrieves a list of URLs, with a 2 second delay between retrievals
# @param    selector    An optional DOM selector for elements containing desired links
# @return               A list of link URLs
def retrieve_multipage(urls, selector="", verbose=False):
    result = []
    for url in urls:
        time.sleep(2)
        if verbose:
            print "Retrieving " + url
        result.extend(filter_links(PyQuery(url=url), selector))
    return result

## Writes a list to a file with a newline separator after each list item
# @param    data        The list to be written
# @param    filename    The output filename
def write_list(data, filename):
    with open(filename, "w") as file:
        for item in data:
            file.write(item)
            file.write("\n")

## Reads a newline separated list from a file
# @param    filename    The filename to be read
# @return               A list of each line from the file
def read_list(filename):
    with open(filename, "r") as file:
        return [item.strip() for item in file.readlines()]

## Returns a list of items that exist in two lists
# @param    list1       A list containing elements
# @param    list2       A second list containing elements
# @return               A list containing elements that exist in both parameters
def intersection(list1, list2):
    return [element for element in set(list1).intersection(list2)]

## Performs a breadth-first web crawl
# @param    start           The starting URL to begin the crawl, or a list of URLs to queue for crawling
# @param    max_articles    The maximum number of articles to retrieve before ending the crawl
# @param    max_depth       The maximum depth of links from the starting article
# @param    accept          A list of URLs that the crawler will follow. Supplying an empty list will result in no data
# @param    reject          A list of URLs that the crawler will NOT follow
# @param    host            A hostname to crawl articles on
# @param    selector        A CSS selector used to select parent elements of links from each crawled article
# @param    title_selector  A CSS selector for the HTML element that contains a page's title. Useful for non-Wikipedia wikis
def crawl(start, \
            max_articles=200, \
            max_depth=3, accept=list(), \
            reject=list(), \
            host="https://en.wikipedia.org", \
            selector=None, \
            title_selector="#firstHeading"):
    from collections import deque
    result = dict()
    crawl_queue = deque()
    import types
    if isinstance(start, list):
        for url in start:
            if url not in crawl_queue:
                crawl_queue.append(url)
    else:
        crawl_queue.append(start)
    count = 0
    while count < max_articles and len(crawl_queue) > 0:
        count = count + 1
        current = crawl_queue.popleft()
        print "{}: Retrieving {}, ({} left in queue)".format(count, current.encode('utf-8'), len(crawl_queue))
        try:
            page = PyQuery(url=host+current)

            # Make sure page exists in structure
            if current not in result:
                result[current] = dict()
                result[current]["depth"] = 0

            # Save page data
            result[current]["title"] = page(title_selector).text()
            result[current]["links"] = [link for link in filter_links(page, selector=selector) if link in accept and link not in reject]

            # Check current depth, don't want to go to deep!
            if result[current]["depth"] <= max_depth:
                for link in result[current]["links"]:
                    if link not in result and link not in crawl_queue:
                        crawl_queue.append(link)
                        result[link] = dict()
                        result[link]["depth"] = result[current]["depth"] + 1

            # Important!!!
            time.sleep(2)
        except:
            print "Error retrieving", host+current

    return result

## Creates a dictionary representing a directed graph from crawl data
# @param    data    A dictionary from the result of @link <crawl>
# @return           A dictionary where each key is an article title, and the value is a dictionary containing the source URL and a list of edges and weights
def directed_graph(data):
    result = dict()
    for item in data:
        current_title = data[item]["title"]
        result[current_title] = dict()
        result[current_title]["url"] = item
        result[current_title]["edges"] = dict()
        for link in data[item]["links"]:
            if link in data:
                link_title = data[link]["title"]
            else:
                link_title = link
            if link_title not in result[current_title]:
                result[current_title]["edges"][link_title] = data[item]["links"].count(link)
    return result

## Creates a dictionary representing an undirected graph from crawl data
# @param    data    A dictionary from the result of @link <crawl>
# @return           A dictionary similar to @link <directed_graph>, except that edges appear exactly once, with a weight that is the sum of links between both articles connected by the edge
def undirected_graph(data):
    result = dict()
    for item in data:
        current_title = data[item]["title"]
        result[current_title] = dict()
        result[current_title]["url"] = item
        result[current_title]["edges"] = dict()
        already_counted = list()
        for link in data[item]["links"]:
            if link not in already_counted:
                if link in data:
                    link_title = data[link]["title"]
                else:
                    link_title = link
                if link_title in result and current_title in result[link_title]["edges"]:
                    result[link_title]["edges"][current_title] += data[item]["links"].count(link)
                elif link_title not in result[current_title]:
                    result[current_title]["edges"][link_title] = data[item]["links"].count(link)
                already_counted.append(link)
    return result

## Saves a dictionary to a file in JSON format
# @param    data        The dictionary to save
# @param    filename    The output filename
# @param    pretty      If True, the output is formatted with indentation and keys are sorted
def save_dict(data, filename, pretty=True):
    import json
    with open(filename, 'w') as f:
        if pretty:
            f.write(json.dumps(data, sort_keys=True, indent=4))
        else:
            json.dump(data, f)
        f.close()

## Reads a dictionary from a file in JSON format
# @param    filename    The input filename
# @return               A dictionary from the JSON file
def load_dict(filename):
    import json
    with open(filename, 'r') as f:
        data = json.load(f)
        return data

<commit_msg>Fixed selector bug<commit_after>from pyquery import PyQuery
import time

## Filters a PyQuery object populated from a Wiki page for links
# @param    selector    An optional DOM selector for elements containing desired links
# @return               A list of link URLs
def filter_links(page, selector=""):
    result = []
    subchildren = PyQuery(page("#mw-content-text " + selector))
    for child in subchildren:
        links = PyQuery(child)("a")
        for link in links:
            linkQuery = PyQuery(link)
            if not linkQuery.hasClass("mw-redirect"):
                href = linkQuery.attr("href")
                if "/wiki/" in href and "#" not in href:
                    result.append(linkQuery.attr("href"))
    return result

## Retrieves a list of URLs, with a 2 second delay between retrievals
# @param    selector    An optional DOM selector for elements containing desired links
# @return               A list of link URLs
def retrieve_multipage(urls, selector="", verbose=False):
    result = []
    for url in urls:
        time.sleep(2)
        if verbose:
            print "Retrieving " + url
        result.extend(filter_links(PyQuery(url=url), selector))
    return result

## Writes a list to a file with a newline separator after each list item
# @param    data        The list to be written
# @param    filename    The output filename
def write_list(data, filename):
    with open(filename, "w") as file:
        for item in data:
            file.write(item)
            file.write("\n")

## Reads a newline separated list from a file
# @param    filename    The filename to be read
# @return               A list of each line from the file
def read_list(filename):
    with open(filename, "r") as file:
        return [item.strip() for item in file.readlines()]

## Returns a list of items that exist in two lists
# @param    list1       A list containing elements
# @param    list2       A second list containing elements
# @return               A list containing elements that exist in both parameters
def intersection(list1, list2):
    return [element for element in set(list1).intersection(list2)]

## Performs a breadth-first web crawl
# @param    start           The starting URL to begin the crawl, or a list of URLs to queue for crawling
# @param    max_articles    The maximum number of articles to retrieve before ending the crawl
# @param    max_depth       The maximum depth of links from the starting article
# @param    accept          A list of URLs that the crawler will follow. Supplying an empty list will result in no data
# @param    reject          A list of URLs that the crawler will NOT follow
# @param    host            A hostname to crawl articles on
# @param    selector        A CSS selector used to select parent elements of links from each crawled article
def crawl(start, \
            max_articles=200, \
            max_depth=3, accept=list(), \
            reject=list(), \
            host="https://en.wikipedia.org", \
            selector="", \
            title_selector="#firstHeading"):
    from collections import deque
    result = dict()
    crawl_queue = deque()
    import types
    if isinstance(start, list):
        for url in start:
            if url not in crawl_queue:
                crawl_queue.append(url)
    else:
        crawl_queue.append(start)
    count = 0
    while count < max_articles and len(crawl_queue) > 0:
        count = count + 1
        current = crawl_queue.popleft()
        print "{}: Retrieving {}, ({} left in queue)".format(count, current.encode('utf-8'), len(crawl_queue))
        try:
            page = PyQuery(url=host+current)

            # Make sure page exists in structure
            if current not in result:
                result[current] = dict()
                result[current]["depth"] = 0

            # Save page data
            result[current]["title"] = page(title_selector).text()
            result[current]["links"] = [link for link in filter_links(page, selector=selector) if link in accept and link not in reject]

            # Check current depth, don't want to go to deep!
            if result[current]["depth"] <= max_depth:
                for link in result[current]["links"]:
                    if link not in result and link not in crawl_queue:
                        crawl_queue.append(link)
                        result[link] = dict()
                        result[link]["depth"] = result[current]["depth"] + 1

            # Important!!!
            time.sleep(2)
        except Exception as ex:
            print "Error retrieving", host+current, ":", ex

    return result

## Creates a dictionary representing a directed graph from crawl data
# @param    data    A dictionary from the result of @link <crawl>
# @return           A dictionary where each key is an article title, and the value is a dictionary containing the source URL and a list of edges and weights
def directed_graph(data):
    result = dict()
    for item in data:
        current_title = data[item]["title"]
        result[current_title] = dict()
        result[current_title]["url"] = item
        result[current_title]["edges"] = dict()
        for link in data[item]["links"]:
            if link in data:
                link_title = data[link]["title"]
            else:
                link_title = link
            if link_title not in result[current_title]:
                result[current_title]["edges"][link_title] = data[item]["links"].count(link)
    return result

## Creates a dictionary representing an undirected graph from crawl data
# @param    data    A dictionary from the result of @link <crawl>
# @return           A dictionary similar to @link <directed_graph>, except that edges appear exactly once, with a weight that is the sum of links between both articles connected by the edge
def undirected_graph(data):
    result = dict()
    for item in data:
        current_title = data[item]["title"]
        result[current_title] = dict()
        result[current_title]["url"] = item
        result[current_title]["edges"] = dict()
        already_counted = list()
        for link in data[item]["links"]:
            if link not in already_counted:
                if link in data:
                    link_title = data[link]["title"]
                else:
                    link_title = link
                if link_title in result and current_title in result[link_title]["edges"]:
                    result[link_title]["edges"][current_title] += data[item]["links"].count(link)
                elif link_title not in result[current_title]:
                    result[current_title]["edges"][link_title] = data[item]["links"].count(link)
                already_counted.append(link)
    return result

## Saves a dictionary to a file in JSON format
# @param    data        The dictionary to save
# @param    filename    The output filename
# @param    pretty      If True, the output is formatted with indentation and keys are sorted
def save_dict(data, filename, pretty=True):
    import json
    with open(filename, 'w') as f:
        if pretty:
            f.write(json.dumps(data, sort_keys=True, indent=4))
        else:
            json.dump(data, f)
        f.close()

## Reads a dictionary from a file in JSON format
# @param    filename    The input filename
# @return               A dictionary from the JSON file
def load_dict(filename):
    import json
    with open(filename, 'r') as f:
        data = json.load(f)
        return data

<|endoftext|>


<commit_before># Copyright (c) Charl P. Botha, TU Delft.
# All rights reserved.
# See COPYRIGHT for details.

"""Module containing base class for devide modules.

author: Charl P. Botha <cpbotha@ieee.org>
"""

#########################################################################
class GenericObject(object):
    """Generic object into which we can stuff whichever attributes we want.
    """
    pass

#########################################################################
class DefaultConfigClass(object):
    pass

#########################################################################
class ModuleBase(object):
    """Base class for all modules.

    Any module wishing to take part in the devide party will have to offer all
    of these methods.
    """

    def __init__(self, module_manager):
        """Perform your module initialisation here.

        Please also call this init method
        (i.e. ModuleBase.__init__(self)).  In your own __init__, you
        should create your view and show it to the user.

        """
        self._module_manager = module_manager

        self._config = DefaultConfigClass()

        # modules should toggle this variable to True once they have
        # initialised and shown their view once.
        self.view_initialised = False

    def close(self):
        """Idempotent method for de-initialising module as far as possible.

        We can't guarantee the calling of __del__, as Python does garbage
        collection and the object might destruct a while after we've removed
        all references to it.

        In addition, with python garbage collection, __del__ can cause
        uncollectable objects, so try to avoid it as far as possible.
        """

        # we neatly get rid of some references
        del self._module_manager

    def get_input_descriptions(self):
        """Returns tuple of input descriptions, mostly used by the graph editor
        to make a nice glyph for this module."""
        raise NotImplementedError

    def set_input(self, idx, input_stream):
        """Attaches input_stream (which is e.g. the output of a previous
        module) to this module's input at position idx.

        If the previous value was None and the current value is not None, it
        signifies a connect and the module should initialise as if it's
        getting a new input.  This usually happens during the first network
        execution AFTER a connection.

        If the previous value was not-None and the new value is None, it
        signifies a disconnect and the module should take the necessary
        actions.  This usually happens immediatly when the user disconnects an
        input

        If the previous value was not-None and the current value is not-None,
        the module should take actions as for a changed input.  This event
        signifies a re-transfer on an already existing connection.  This can
        be considered an event for which this module is an observer.
        """

        raise NotImplementedError

    def get_output_descriptions(self):
        """Returns a tuple of output descriptions.

        Mostly used by the graph editor to make a nice glyph for this module.
        These are also clues to the user as to which glyphs can be connected.
        """
        raise NotImplementedError

    def get_output(self, idx):
	"""Get the n-th output.

        This will be used for connecting this output to the input of another
        module.  Whatever is returned by this object MUST have an Update()
        method.  However you choose to implement it, the Update() should make
        sure that the whole chain of logic resulting in the data object has
        executed so that the data object is up to date.
        """
	raise NotImplementedError

    def logic_to_config(self):
        """Synchronise internal configuration information (usually
        self._config)with underlying system.

        You only need to implement this if you make use of the standard ECASH
        controls.
        """
        raise NotImplementedError

    def config_to_logic(self):
        """Apply internal configuration information (usually self._config) to
        the underlying logic.

        If this has resulted in changes to the logic, return True, otherwise
        return False

        You only need to implement this if you make use of the standard ECASH
        controls.
        """

        raise NotImplementedError

    def view_to_config(self):
        """Synchronise internal configuration information with the view (GUI)
        of this module.

        If this has resulted in changes to the config, return True,
        otherwise return False.

        You only need to implement this if you make use of the standard ECASH
        controls.
        """
        raise NotImplementedError

    def config_to_view(self):
        """Make the view reflect the internal configuration information.

        You only need to implement this if you make use of the standard ECASH
        controls.
        """
        raise NotImplementedError

    def execute_module(self):
        """This should make the model do whatever processing it was designed
        to do.

        It's important that when this method is called, the module should be
        able to cause ALL of the modules preceding it in a glyph chain to
        execute (if necessary).  If the whole chain consists of VTK objects,
        this is easy.

        If not, extra measures need to be taken.  According to API,
        each output/input data object MUST have an Update() method
        that can ensure that the logic responsible for that object has
        executed thus making the data object current.

        In short, execute_module() should call Update() on all of this modules
        input objects, directly or indirectly.
        """
        raise NotImplementedError

    def view(self):
        """Pop up a dialog with all config possibilities, including optional
        use of the pipeline browser.

        If the dialog is already visible, do something to draw the user's
        attention to it.  For a wxFrame-based view, you can do something like:
        if not frame.Show(True):
            frame.Raise()
        If the frame is already visible, this will bring it to the front.
        """
        raise NotImplementedError

    def get_config(self):
        """Returns current configuration of module.

        This should return a pickle()able object that encapsulates all
        configuration information of this module.  The default just returns
        self._config, which is None by default.  You can override get_config()
        and set_config(), or just make sure that your config info always goes
        via self._config

        In general, you should never need to override this.
        """

        # make sure that the config reflects the state of the underlying logic
        self.logic_to_config()
        # and then return the config struct.
        return self._config

    def set_config(self, aConfig):
        """Change configuration of module to that stored in aConfig.

        If set_config is called with the object previously returned by
        get_config(), the module should be in exactly the same state as it was
        when get_config() was called.  The default sets the default
        self._config and applies it to the underlying logic.

        In general, you should never need to override this.
        """

        # we update the dict of the existing config with the passed
        # parameter.  This means that the new config is merged with
        # the old, but all new members overwrite old one.  This is
        # more robust.
        self._config.__dict__.update(aConfig.__dict__)
        # apply the config to the underlying logic
        self.config_to_logic()
        # bring it back all the way up to the view
        self.logic_to_config()

        # but only if we are in view mode
        if self.view_initialised:
            self.config_to_view()

        # the config has been set, so we assumem that the module has
        # now been modified.
        self._module_manager.modify_module(self)

    # convenience functions

    def sync_module_logic_with_config(self):
        self._module_manager.sync_module_logic_with_config(self)

    def sync_module_view_with_config(self):
        self._module_manager.sync_module_view_with_config(self)

    def sync_module_view_with_logic(self):
        self._module_manager.sync_module_view_with_logic(self)

<commit_msg>White space changes.<commit_after># Copyright (c) Charl P. Botha, TU Delft.
# All rights reserved.
# See COPYRIGHT for details.

"""Module containing base class for devide modules.

author: Charl P. Botha <cpbotha@ieee.org>
"""

#########################################################################
class GenericObject(object):
    """Generic object into which we can stuff whichever attributes we want.
    """
    pass

#########################################################################
class DefaultConfigClass(object):
    pass

#########################################################################
class ModuleBase(object):
    """Base class for all modules.

    Any module wishing to take part in the devide party will have to offer all
    of these methods.
    """

    def __init__(self, module_manager):
        """Perform your module initialisation here.

        Please also call this init method
        (i.e. ModuleBase.__init__(self)).  In your own __init__, you
        should create your view and show it to the user.

        """
        self._module_manager = module_manager

        self._config = DefaultConfigClass()

        # modules should toggle this variable to True once they have
        # initialised and shown their view once.
        self.view_initialised = False

    def close(self):
        """Idempotent method for de-initialising module as far as possible.

        We can't guarantee the calling of __del__, as Python does garbage
        collection and the object might destruct a while after we've removed
        all references to it.

        In addition, with python garbage collection, __del__ can cause
        uncollectable objects, so try to avoid it as far as possible.
        """

        # we neatly get rid of some references
        del self._module_manager

    def get_input_descriptions(self):
        """Returns tuple of input descriptions, mostly used by the graph editor
        to make a nice glyph for this module."""
        raise NotImplementedError

    def set_input(self, idx, input_stream):
        """Attaches input_stream (which is e.g. the output of a previous
        module) to this module's input at position idx.

        If the previous value was None and the current value is not None, it
        signifies a connect and the module should initialise as if it's
        getting a new input.  This usually happens during the first network
        execution AFTER a connection.

        If the previous value was not-None and the new value is None, it
        signifies a disconnect and the module should take the necessary
        actions.  This usually happens immediatly when the user disconnects an
        input

        If the previous value was not-None and the current value is not-None,
        the module should take actions as for a changed input.  This event
        signifies a re-transfer on an already existing connection.  This can
        be considered an event for which this module is an observer.
        """

        raise NotImplementedError

    def get_output_descriptions(self):
        """Returns a tuple of output descriptions.

        Mostly used by the graph editor to make a nice glyph for this module.
        These are also clues to the user as to which glyphs can be connected.
        """
        raise NotImplementedError

    def get_output(self, idx):
        """Get the n-th output.

        This will be used for connecting this output to the input of another
        module.  Whatever is returned by this object MUST have an Update()
        method.  However you choose to implement it, the Update() should make
        sure that the whole chain of logic resulting in the data object has
        executed so that the data object is up to date.
        """
        raise NotImplementedError

    def logic_to_config(self):
        """Synchronise internal configuration information (usually
        self._config)with underlying system.

        You only need to implement this if you make use of the standard ECASH
        controls.
        """
        raise NotImplementedError

    def config_to_logic(self):
        """Apply internal configuration information (usually self._config) to
        the underlying logic.

        If this has resulted in changes to the logic, return True, otherwise
        return False

        You only need to implement this if you make use of the standard ECASH
        controls.
        """

        raise NotImplementedError

    def view_to_config(self):
        """Synchronise internal configuration information with the view (GUI)
        of this module.

        If this has resulted in changes to the config, return True,
        otherwise return False.

        You only need to implement this if you make use of the standard ECASH
        controls.
        """
        raise NotImplementedError

    def config_to_view(self):
        """Make the view reflect the internal configuration information.

        You only need to implement this if you make use of the standard ECASH
        controls.
        """
        raise NotImplementedError

    def execute_module(self):
        """This should make the model do whatever processing it was designed
        to do.

        It's important that when this method is called, the module should be
        able to cause ALL of the modules preceding it in a glyph chain to
        execute (if necessary).  If the whole chain consists of VTK objects,
        this is easy.

        If not, extra measures need to be taken.  According to API,
        each output/input data object MUST have an Update() method
        that can ensure that the logic responsible for that object has
        executed thus making the data object current.

        In short, execute_module() should call Update() on all of this modules
        input objects, directly or indirectly.
        """
        raise NotImplementedError

    def view(self):
        """Pop up a dialog with all config possibilities, including optional
        use of the pipeline browser.

        If the dialog is already visible, do something to draw the user's
        attention to it.  For a wxFrame-based view, you can do something like:
        if not frame.Show(True):
            frame.Raise()
        If the frame is already visible, this will bring it to the front.
        """
        raise NotImplementedError

    def get_config(self):
        """Returns current configuration of module.

        This should return a pickle()able object that encapsulates all
        configuration information of this module.  The default just returns
        self._config, which is None by default.  You can override get_config()
        and set_config(), or just make sure that your config info always goes
        via self._config

        In general, you should never need to override this.
        """

        # make sure that the config reflects the state of the underlying logic
        self.logic_to_config()
        # and then return the config struct.
        return self._config

    def set_config(self, aConfig):
        """Change configuration of module to that stored in aConfig.

        If set_config is called with the object previously returned by
        get_config(), the module should be in exactly the same state as it was
        when get_config() was called.  The default sets the default
        self._config and applies it to the underlying logic.

        In general, you should never need to override this.
        """

        # we update the dict of the existing config with the passed
        # parameter.  This means that the new config is merged with
        # the old, but all new members overwrite old one.  This is
        # more robust.
        self._config.__dict__.update(aConfig.__dict__)
        # apply the config to the underlying logic
        self.config_to_logic()
        # bring it back all the way up to the view
        self.logic_to_config()

        # but only if we are in view mode
        if self.view_initialised:
            self.config_to_view()

        # the config has been set, so we assumem that the module has
        # now been modified.
        self._module_manager.modify_module(self)

    # convenience functions

    def sync_module_logic_with_config(self):
        self._module_manager.sync_module_logic_with_config(self)

    def sync_module_view_with_config(self):
        self._module_manager.sync_module_view_with_config(self)

    def sync_module_view_with_logic(self):
        self._module_manager.sync_module_view_with_logic(self)

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

__version__ = '0.3.3'<commit_msg>versionbump 0.3.4<commit_after># -*- coding: utf-8 -*-

__version__ = '0.3.4'<|endoftext|>


<commit_before># $Id: module_base.py,v 1.17 2002/06/10 16:58:33 cpbotha Exp $

# ----------------------------------------------------------------------------

"""Module containing class-related utilities and code for dscas3 modules.

In this module you'll find a base class as well as several useful mixins.
Please see the documentation.

author: Charl P. Botha <cpbotha@ieee.org>
"""

class module_base:
    """Base class for all modules.

    Any module wishing to take part in the dscas3 party will have to offer all
    of these methods.
    """

    def __init__(self, module_manager):
        """We need to know where the module manager is so we can query
        it about the module path, e.g.
        """
        self._module_manager = module_manager

    def close(self):
	"""Idempotent method for de-initialising module as far as possible.

        We can't guarantee the calling of __del__, as Python does garbage
        collection and the object might destruct a while after we've removed
        all references to it.

        In addition, with python garbage collection, __del__ can cause
        uncollectable objects, so try to avoid it as far as possible.
        """
	raise NotImplementedError

    def get_input_descriptions(self):
	"""Returns tuple of input descriptions, mostly used by the graph editor
	to make a nice glyph for this module."""
	raise NotImplementedError

    def set_input(self, idx, input_stream):
	"""Attaches input_stream (which is e.g. the output of a previous
        module) to this module's input at position idx.
        """
	raise NotImplementedError

    def get_output_descriptions(self):
	"""Returns a tuple of output descriptions.

        Mostly used by the graph editor to make a nice glyph for this module.
        These are also clues to the user as to which glyphs can be connected.
        """
	raise NotImplementedError

    def get_output(self, idx):
	"""Get the n-th output.

        This will be used for connecting this output to the input of another
        module.
        """
	raise NotImplementedError

    def sync_config(self):
	raise NotImplementedError

    def apply_config(self):
	raise NotImplementedError

    def execute_module(self):
	raise NotImplementedError

    def view(self):
	"""Pop up a dialog with all config possibilities, including optional
        use of the pipeline browser.
        """
	raise NotImplementedError

# ----------------------------------------------------------------------------

from external.vtkPipeline.ConfigVtkObj import ConfigVtkObj
from external.vtkPipeline.vtkPipeline import vtkPipelineBrowser

class module_mixin_vtk_pipeline_config:
    """Mixin to use for modules that want to make use of the vtkPipeline
    functionality.

    Modules that use this as mixin can make use of the vtk_object_configure
    and vtk_pipeline_configure methods to use ConfigVtkObj and
    vtkPipelineBrowser, respectively.  These methods will make sure that you
    use only one instance of a browser/config class per object.
    """

    def vtk_object_configure(self, parent, renwin, vtk_obj):
        """This will instantiate and show only one object config frame per
        unique vtk_obj (per module instance).

        If it is called multiple times for the same object, it will merely
        bring the pertinent window to the top (by show()ing).

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroyed.
        renwin: render window (optionally None) which will be
        render()ed when changes are made to the vtk object which is being
        configured.
        vtk_obj: the object you want to config.
        """
        if not hasattr(self, '_vtk_obj_cfs'):
            self._vtk_obj_cfs = {}
        if not self._vtk_obj_cfs.has_key(vtk_obj):
            self._vtk_obj_cfs[vtk_obj] = ConfigVtkObj(parent, renwin, vtk_obj)
        self._vtk_obj_cfs[vtk_obj].show()

    def close_vtk_object_configure(self):
        """Explicitly close() all ConfigVtkObj's that vtk_objct_configure has
        created.

        Usually, the ConfigVtkObj windows will be children of some frame, and
        when that frame gets destroyed, they will be too.  However, when this
        is not the case, you can make use of this method.
        """
        if hasattr(self, '_vtk_obj_cfs'):
            for key in self._vtk_obj_cfs.keys():
                self._vtk_obj_cfs[key].close()
            self._vtk_obj_cfs.clear()

    def vtk_pipeline_configure(self, parent, renwin, objects=None):
        """This will instantiate and show only one pipeline config per
        module instance.

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroy()ed.
        renwin: render window (optionally None) which will be render()ed
        when changes are made AND if objects is None, will be used to determine
        the pipeline.
        objects: if you don't want the pipeline to be extracted from the
        renderwindow, you can specify a sequence of objects to be used as the
        multiple roots of a partial pipeline.

        NOTE: renwin and objects can't BOTH be None/empty.
        """
        if not hasattr(self, '_pipeline') or self._pipeline == None:
            self._pipeline = vtkPipelineBrowser(parent, renwin, objects)
        self._pipeline.show()

    def close_pipeline_configure(self):
        """Explicitly close() the pipeline browser of this module.

        This should happen automatically if a valid 'parent' was passed to
        vtk_pipeline_configure(), i.e. when the parent dies, the pipeline
        browser will die too.  However, you can use this method to take
        care of it explicitly.
        """
        if hasattr(self, '_pipeline'):
            self._pipeline.close()
        self._pipeline = None

# ----------------------------------------------------------------------------

from wxPython.wx import wxFileDialog, wxOPEN, wxID_OK

class module_mixin_fo_dialog:
    """Module mixin to make use of file open dialog."""

    def fn_browse(self, parent, message, wildcard, style=wxOPEN):
        """Utility method to make use of wxFileDialog.

        This function will open up exactly one dialog per 'message' and this
        dialog won't be destroyed.  This persistence makes sure that the dialog
        retains its previous settings and also that there is less overhead for
        subsequent creations.  The dialog will be a child of 'parent', so when
        parent is destroyed, this dialog will be too.
        """
        if not hasattr(self, '_fo_dlgs'):
            self._fo_dlgs = {}
        if not self._fo_dlgs.has_key(message):
            self._fo_dlgs[message] = wxFileDialog(parent,
                                                  message, "", "",
                                                  wildcard, style)
        if self._fo_dlgs[message].ShowModal() == wxID_OK:
            return self._fo_dlgs[message].GetPath()
        else:
            return None

    def close_fn_browse(self):
        """Use this method to close all created dialogs explicitly.

        This should be taken care of automatically if you've passed in a valid
        'parent'.  Use this method in cases where this was not possible.
        """
        if hasattr(self, '_fo_dlgs'):
            for key in self._fo_dlgs.keys():
                self._fo_dlgs[key].Destroy()
            self._fo_dlgs.clear()
<commit_msg>Added wxDirDialog functionality.<commit_after># $Id: module_base.py,v 1.18 2002/08/16 11:46:24 cpbotha Exp $

# ----------------------------------------------------------------------------

"""Module containing class-related utilities and code for dscas3 modules.

In this module you'll find a base class as well as several useful mixins.
Please see the documentation.

author: Charl P. Botha <cpbotha@ieee.org>
"""

class module_base:
    """Base class for all modules.

    Any module wishing to take part in the dscas3 party will have to offer all
    of these methods.
    """

    def __init__(self, module_manager):
        """We need to know where the module manager is so we can query
        it about the module path, e.g.
        """
        self._module_manager = module_manager

    def close(self):
	"""Idempotent method for de-initialising module as far as possible.

        We can't guarantee the calling of __del__, as Python does garbage
        collection and the object might destruct a while after we've removed
        all references to it.

        In addition, with python garbage collection, __del__ can cause
        uncollectable objects, so try to avoid it as far as possible.
        """
	raise NotImplementedError

    def get_input_descriptions(self):
	"""Returns tuple of input descriptions, mostly used by the graph editor
	to make a nice glyph for this module."""
	raise NotImplementedError

    def set_input(self, idx, input_stream):
	"""Attaches input_stream (which is e.g. the output of a previous
        module) to this module's input at position idx.
        """
	raise NotImplementedError

    def get_output_descriptions(self):
	"""Returns a tuple of output descriptions.

        Mostly used by the graph editor to make a nice glyph for this module.
        These are also clues to the user as to which glyphs can be connected.
        """
	raise NotImplementedError

    def get_output(self, idx):
	"""Get the n-th output.

        This will be used for connecting this output to the input of another
        module.
        """
	raise NotImplementedError

    def sync_config(self):
	raise NotImplementedError

    def apply_config(self):
	raise NotImplementedError

    def execute_module(self):
	raise NotImplementedError

    def view(self):
	"""Pop up a dialog with all config possibilities, including optional
        use of the pipeline browser.
        """
	raise NotImplementedError

# ----------------------------------------------------------------------------

from external.vtkPipeline.ConfigVtkObj import ConfigVtkObj
from external.vtkPipeline.vtkPipeline import vtkPipelineBrowser

class module_mixin_vtk_pipeline_config:
    """Mixin to use for modules that want to make use of the vtkPipeline
    functionality.

    Modules that use this as mixin can make use of the vtk_object_configure
    and vtk_pipeline_configure methods to use ConfigVtkObj and
    vtkPipelineBrowser, respectively.  These methods will make sure that you
    use only one instance of a browser/config class per object.
    """

    def vtk_object_configure(self, parent, renwin, vtk_obj):
        """This will instantiate and show only one object config frame per
        unique vtk_obj (per module instance).

        If it is called multiple times for the same object, it will merely
        bring the pertinent window to the top (by show()ing).

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroyed.
        renwin: render window (optionally None) which will be
        render()ed when changes are made to the vtk object which is being
        configured.
        vtk_obj: the object you want to config.
        """
        if not hasattr(self, '_vtk_obj_cfs'):
            self._vtk_obj_cfs = {}
        if not self._vtk_obj_cfs.has_key(vtk_obj):
            self._vtk_obj_cfs[vtk_obj] = ConfigVtkObj(parent, renwin, vtk_obj)
        self._vtk_obj_cfs[vtk_obj].show()

    def close_vtk_object_configure(self):
        """Explicitly close() all ConfigVtkObj's that vtk_objct_configure has
        created.

        Usually, the ConfigVtkObj windows will be children of some frame, and
        when that frame gets destroyed, they will be too.  However, when this
        is not the case, you can make use of this method.
        """
        if hasattr(self, '_vtk_obj_cfs'):
            for key in self._vtk_obj_cfs.keys():
                self._vtk_obj_cfs[key].close()
            self._vtk_obj_cfs.clear()

    def vtk_pipeline_configure(self, parent, renwin, objects=None):
        """This will instantiate and show only one pipeline config per
        module instance.

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroy()ed.
        renwin: render window (optionally None) which will be render()ed
        when changes are made AND if objects is None, will be used to determine
        the pipeline.
        objects: if you don't want the pipeline to be extracted from the
        renderwindow, you can specify a sequence of objects to be used as the
        multiple roots of a partial pipeline.

        NOTE: renwin and objects can't BOTH be None/empty.
        """
        if not hasattr(self, '_pipeline') or self._pipeline == None:
            self._pipeline = vtkPipelineBrowser(parent, renwin, objects)
        self._pipeline.show()

    def close_pipeline_configure(self):
        """Explicitly close() the pipeline browser of this module.

        This should happen automatically if a valid 'parent' was passed to
        vtk_pipeline_configure(), i.e. when the parent dies, the pipeline
        browser will die too.  However, you can use this method to take
        care of it explicitly.
        """
        if hasattr(self, '_pipeline'):
            self._pipeline.close()
        self._pipeline = None

# ----------------------------------------------------------------------------

from wxPython.wx import wxFileDialog, wxDirDialog, wxOPEN, wxID_OK

class module_mixin_fo_dialog:
    """Module mixin to make use of file open dialog."""

    def fn_browse(self, parent, message, wildcard, style=wxOPEN):
        """Utility method to make use of wxFileDialog.

        This function will open up exactly one dialog per 'message' and this
        dialog won't be destroyed.  This persistence makes sure that the dialog
        retains its previous settings and also that there is less overhead for
        subsequent creations.  The dialog will be a child of 'parent', so when
        parent is destroyed, this dialog will be too.
        """
        if not hasattr(self, '_fo_dlgs'):
            self._fo_dlgs = {}
        if not self._fo_dlgs.has_key(message):
            self._fo_dlgs[message] = wxFileDialog(parent,
                                                  message, "", "",
                                                  wildcard, style)
        if self._fo_dlgs[message].ShowModal() == wxID_OK:
            return self._fo_dlgs[message].GetPath()
        else:
            return None

    def close_fn_browse(self):
        """Use this method to close all created dialogs explicitly.

        This should be taken care of automatically if you've passed in a valid
        'parent'.  Use this method in cases where this was not possible.
        """
        if hasattr(self, '_fo_dlgs'):
            for key in self._fo_dlgs.keys():
                self._fo_dlgs[key].Destroy()
            self._fo_dlgs.clear()

    def dn_browse(self, parent, message, default_path=""):
        """Utility method to make use of wxDirDialog.

        This function will open up exactly one dialog per 'message' and this
        dialog won't be destroyed.  This function is more or less identical
        to fn_browse().
        """
        if not hasattr(self, '_do_dlgs'):
            self._do_dlgs = {}

        if not self._do_dlgs.has_key(message):
            self._do_dlgs[message] = wxDirDialog(parent, message, default_path)

        if self._do_dlgs[message].ShowModal() == wxID_OK:
            return self._do_dlgs[message].GetPath()
        else:
            return None

<|endoftext|>