def checkBasicOps(self): from persistent.mapping import PersistentMapping m = PersistentMapping({'x': 1}, a=2, b=3) m['name'] = 'bob' self.assertEqual(m['name'], "bob") self.assertEqual(m.get('name', 42), "bob") self.assert_('name' in m) try: m['fred'] except KeyError: pass else: self.fail("expected KeyError") self.assert_('fred' not in m) self.assertEqual(m.get('fred'), None) self.assertEqual(m.get('fred', 42), 42) keys = m.keys() keys.sort() self.assertEqual(keys, ['a', 'b', 'name', 'x']) values = m.values() values.sort() self.assertEqual(values, [1, 2, 3, 'bob']) items = m.items() items.sort() self.assertEqual(items, [('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)]) keys = list(m.iterkeys()) keys.sort() self.assertEqual(keys, ['a', 'b', 'name', 'x']) values = list(m.itervalues()) values.sort() self.assertEqual(values, [1, 2, 3, 'bob']) items = list(m.iteritems()) items.sort() self.assertEqual(items, [('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)])
def checkBasicOps(self): from persistent.mapping import PersistentMapping m = PersistentMapping({'x': 1}, a=2, b=3) m['name'] = 'bob' self.assertEqual(m['name'], "bob") self.assertEqual(m.get('name', 42), "bob") self.assert_('name' in m) try: m['fred'] except KeyError: pass else: self.fail("expected KeyError") self.assert_('fred' not in m) self.assertEqual(m.get('fred'), None) self.assertEqual(m.get('fred', 42), 42) keys = m.keys() keys.sort() self.assertEqual(keys, ['a', 'b', 'name', 'x']) values = m.values() values.sort() self.assertEqual(values, [1, 2, 3, 'bob']) items = m.items() items.sort() self.assertEqual(items, [('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)]) keys = list(m.iterkeys()) keys.sort() self.assertEqual(keys, ['a', 'b', 'name', 'x']) values = list(m.itervalues()) values.sort() self.assertEqual(values, [1, 2, 3, 'bob']) items = list(m.iteritems()) items.sort() self.assertEqual(items, [('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)])
def checkBasicOps(self): from persistent.mapping import PersistentMapping m = PersistentMapping({"x": 1}, a=2, b=3) m["name"] = "bob" self.assertEqual(m["name"], "bob") self.assertEqual(m.get("name", 42), "bob") self.assert_("name" in m) try: m["fred"] except KeyError: pass else: self.fail("expected KeyError") self.assert_("fred" not in m) self.assertEqual(m.get("fred"), None) self.assertEqual(m.get("fred", 42), 42) keys = m.keys() keys.sort() self.assertEqual(keys, ["a", "b", "name", "x"]) values = m.values() values.sort() self.assertEqual(values, [1, 2, 3, "bob"]) items = m.items() items.sort() self.assertEqual(items, [("a", 2), ("b", 3), ("name", "bob"), ("x", 1)]) keys = list(m.iterkeys()) keys.sort() self.assertEqual(keys, ["a", "b", "name", "x"]) values = list(m.itervalues()) values.sort() self.assertEqual(values, [1, 2, 3, "bob"]) items = list(m.iteritems()) items.sort() self.assertEqual(items, [("a", 2), ("b", 3), ("name", "bob"), ("x", 1)])
class PatchedDirectory (FileMeta): ftype = fs.DIRECTORY EXISTING = 0 ADDED = 1 REMOVED = 2 def __init__(self, name, parent, uid, gid, mode, mtime_ns): FileMeta.__init__(self, name, parent, uid, gid, mode, mtime_ns) self.adds = PersistentMapping() self.removes = PersistentMapping() self.meta_changes = PersistentMapping() # name => ((to_uid, to_gid, to_mode), (from_uid, from_gid, from_mode)) self.subdirs = PersistentMapping() self.state = PatchedDirectory.EXISTING def pdbg(self, indent = ''): s = { 0 : 'EXISTING', 1 : 'ADDED', 2 : 'REMOVED' } print indent, 'Dir %s %s' % (s[self.state], self.dbg_meta()) if self.adds: print indent, ' ** Adds **' for v in self.adds.itervalues(): v.pdbg( indent + ' ' ) if self.removes: print indent, ' ** Removes **' for v in self.removes.itervalues(): v.pdbg( indent + ' ' ) if self.meta_changes: print indent, ' ** Meta Mods **' for k, v in self.removes.iteritems(): print indent + ' ', k, v for s in self.subdirs.itervalues(): s.pdbg( indent + ' ' )
class Book( Persistent ): ''' This is a user book to include user's orders, one per user ''' def __init__(self, user=None): self.user = user self.orders = PersistentList() self.positions = PersistentMapping() def addOrder(self, order): if order.instrument in self.positions: self.positions[order.instrument].append(order) else: self.positions[order.instrument] = PersistentList(order) def cost(self): cost=0.0 for orders in self.positions.itervalues(): cost += sum([o.cost() for o in orders]) return def marketValue(self): mktval = 0.0 for inst, orders in self.positions.iteritems(): mktval += inst.marketPrice * sum([o.amountMatched for o in orders]) return mktval
class Book( Persistent ): ''' This is a user book to include user's orders, one per user ''' def __init__(self, user=None): self.user = user self.orders = PersistentList() self.positions = PersistentMapping() def addOrder(self, order): if order.instrument in self.positions: self.positions[order.instrument].append(order) else: self.positions[order.instrument] = PersistentList(order) def cost(self): cost=0.0 for orders in self.positions.itervalues(): cost += sum([o.cost() for o in orders]) return def marketValue(self): mktval = 0.0 for inst, orders in self.positions.iteritems(): mktval += inst.marketPrice * sum([o.amountMatched for o in orders]) return mktval
class PasswordResetTool(SimpleItem): meta_type = 'Eionet Password Reset Tool' security = ClassSecurityInfo() icon = '++resource++eea.ldapadmin-www/eionet_password_reset_tool.gif' session_messages = SESSION_MESSAGES manage_options = ( {'label': 'Configure', 'action': 'manage_edit'}, {'label': 'View', 'action': ''}, ) + SimpleItem.manage_options _render_template = TemplateRenderer(CommonTemplateLogic) def __init__(self, config={}): super(PasswordResetTool, self).__init__() self._config = PersistentMapping(config) self._tokens = PersistentMapping() security.declareProtected(view_management_screens, 'get_config') def get_config(self): return dict(self._config) security.declareProtected(view_management_screens, 'manage_edit') manage_edit = PageTemplateFile('zpt/pwreset_manage_edit', globals()) manage_edit.ldap_config_edit_macro = ldap_config.edit_macro security.declareProtected(view_management_screens, 'manage_edit_save') def manage_edit_save(self, REQUEST): """ save changes to configuration """ form = REQUEST.form new_config = ldap_config.read_form(form, edit=True) new_config['legacy_ldap_server'] = form.get('legacy_ldap_server', '') new_config['legacy_admin_dn'] = form.get('legacy_admin_dn', '') new_config['legacy_admin_pw'] = form.get('legacy_admin_pw', '') if not new_config['legacy_admin_pw']: del new_config['legacy_admin_pw'] # don't overwrite self._config.update(new_config) REQUEST.RESPONSE.redirect(self.absolute_url() + '/manage_edit') def _get_ldap_agent(self, bind=True): return ldap_config.ldap_agent_with_config(self._config, bind) def _predefined_filters(self): return sorted(self.objectValues([query.Query.meta_type]), key=lambda ob: ob.getId()) security.declareProtected(view, 'index_html') def index_html(self, REQUEST): """ view """ email = REQUEST.get('email', '') options = {'email': email} return self._render_template('zpt/pwreset_index.zpt', **options) def _new_token(self, user_id): token = random_token() self._tokens[token] = TokenData(user_id, datetime.utcnow()) return token def _send_token_email(self, addr_to, token, user_info): addr_from = "*****@*****.**" email_template = load_template('zpt/pwreset_token_email.zpt') expiration_time = datetime.utcnow() + timedelta(days=1) options = { 'token_url': self.absolute_url() + "/confirm_email?token=" + token, 'user_info': user_info, 'context': self, 'network_name': NETWORK_NAME, 'expiration_time': expiration_time.strftime("%Y-%m-%d %H:%M:%S") } print options['token_url'] message = MIMEText(email_template(**options).encode('utf-8'), _charset='utf-8') message['From'] = addr_from message['To'] = addr_to message['Subject'] = "%s account password recovery" % NETWORK_NAME try: mailer = getUtility(IMailDelivery, name="Mail") mailer.send(addr_from, [addr_to], message.as_string()) except ComponentLookupError: mailer = getUtility(IMailDelivery, name="naaya-mail-delivery") try: mailer.send(addr_from, [addr_to], message.as_string()) except AssertionError: mailer.send(addr_from, [addr_to], message) security.declareProtected(view, 'ask_for_password_reset') def ask_for_password_reset(self, REQUEST=None, email=None): """ view """ if REQUEST is None: REQUEST = self.REQUEST if not email: email = REQUEST.form['email'] agent = self._get_ldap_agent() users = agent.search_user_by_email(email) # , no_disabled=True) if users: # some people have multiple accounts; send mail for each account. for user_info in users: if user_info['status'] == 'disabled': msg = "This email: %s belongs to a disabled account" % \ user_info['email'] _set_session_message(REQUEST, 'error', msg) location = ( self.absolute_url() + '/messages_html?msg=email-disabled') else: token = self._new_token(user_info['id']) log.info( "Sending password recovery email to user %r at %r.", user_info['id'], email) self._send_token_email(email, token, user_info) location = (self.absolute_url() + '/messages_html?msg=email-sent') else: log.info("Requested password recovery with invalid email %r.", email) msg = "Email address not found in database." _set_session_message(REQUEST, 'error', msg) location = self.absolute_url() + '/' if REQUEST: REQUEST.RESPONSE.redirect(location) security.declareProtected(view, 'messages_html') def messages_html(self, REQUEST): """ view """ options = { 'message-name': REQUEST.form['msg'], } return self._render_template('zpt/pwreset_message.zpt', **options) def _say_token_expired(self, REQUEST): msg = ("Password reset link is invalid, perhaps it has " "expired. Please try again.") _set_session_message(REQUEST, 'error', msg) location = self.absolute_url() + '/' REQUEST.RESPONSE.redirect(location) def _expire_tokens(self): expired = [] cutoff_time = datetime.utcnow() - timedelta(days=1) for token, token_data in self._tokens.iteritems(): if token_data.timestamp < cutoff_time: expired.append(token) for token in expired: log.info('Token %r expired.', token) del self._tokens[token] security.declareProtected(view, 'confirm_email') def confirm_email(self, REQUEST): """ view """ token = REQUEST.form['token'] self._expire_tokens() token_data = self._tokens.get(token, None) if token_data is None: return self._say_token_expired(REQUEST) options = { 'token': token, 'user_id': token_data.user_id, } return self._render_template('zpt/pwreset_new_password.zpt', **options) def reset_password(self, REQUEST): """ view """ token = REQUEST.form['token'] self._expire_tokens() token_data = self._tokens.get(token, None) if token_data is None: return self._say_token_expired(REQUEST) new_password = REQUEST.form['password'] if new_password != REQUEST.form['password-confirm']: _set_session_message(REQUEST, 'error', "Passwords do not match.") location = self.absolute_url() + '/confirm_email?token=' + token else: log.info("Restting password for user %r with token %r", token_data.user_id, token) agent = self._get_ldap_agent(bind=True) agent.set_user_password(token_data.user_id, None, new_password) del self._tokens[token] location = (self.absolute_url() + '/messages_html?msg=password-reset') REQUEST.RESPONSE.redirect(location) security.declareProtected(view, 'can_edit_users') def can_edit_users(self): user = self.REQUEST.AUTHENTICATED_USER return bool(user.has_permission(eionet_edit_users, self))
class PasswordResetTool(SimpleItem): meta_type = 'Eionet Password Reset Tool' security = ClassSecurityInfo() icon = '++resource++eea.ldapadmin-www/eionet_password_reset_tool.gif' session_messages = SESSION_MESSAGES manage_options = ( { 'label': 'Configure', 'action': 'manage_edit' }, { 'label': 'View', 'action': '' }, ) + SimpleItem.manage_options _render_template = TemplateRenderer(CommonTemplateLogic) def __init__(self, config={}): super(PasswordResetTool, self).__init__() self._config = PersistentMapping(config) self._tokens = PersistentMapping() security.declareProtected(view_management_screens, 'get_config') def get_config(self): return dict(self._config) security.declareProtected(view_management_screens, 'manage_edit') manage_edit = PageTemplateFile('zpt/pwreset_manage_edit', globals()) manage_edit.ldap_config_edit_macro = ldap_config.edit_macro security.declareProtected(view_management_screens, 'manage_edit_save') def manage_edit_save(self, REQUEST): """ save changes to configuration """ form = REQUEST.form new_config = ldap_config.read_form(form, edit=True) new_config['legacy_ldap_server'] = form.get('legacy_ldap_server', '') new_config['legacy_admin_dn'] = form.get('legacy_admin_dn', '') new_config['legacy_admin_pw'] = form.get('legacy_admin_pw', '') if not new_config['legacy_admin_pw']: del new_config['legacy_admin_pw'] # don't overwrite self._config.update(new_config) REQUEST.RESPONSE.redirect(self.absolute_url() + '/manage_edit') def _get_ldap_agent(self, bind=True): return ldap_config.ldap_agent_with_config(self._config, bind) def _predefined_filters(self): return sorted(self.objectValues([query.Query.meta_type]), key=lambda ob: ob.getId()) security.declareProtected(view, 'index_html') def index_html(self, REQUEST): """ view """ email = REQUEST.get('email', '') options = {'email': email} return self._render_template('zpt/pwreset_index.zpt', **options) def _new_token(self, user_id): token = random_token() self._tokens[token] = TokenData(user_id, datetime.utcnow()) return token def _send_token_email(self, addr_to, token, user_info): addr_from = "*****@*****.**" email_template = load_template('zpt/pwreset_token_email.zpt') expiration_time = datetime.utcnow() + timedelta(days=1) options = { 'token_url': self.absolute_url() + "/confirm_email?token=" + token, 'user_info': user_info, 'context': self, 'network_name': NETWORK_NAME, 'expiration_time': expiration_time.strftime("%Y-%m-%d %H:%M:%S") } print options['token_url'] message = MIMEText(email_template(**options).encode('utf-8'), _charset='utf-8') message['From'] = addr_from message['To'] = addr_to message['Subject'] = "%s account password recovery" % NETWORK_NAME try: mailer = getUtility(IMailDelivery, name="Mail") mailer.send(addr_from, [addr_to], message.as_string()) except ComponentLookupError: mailer = getUtility(IMailDelivery, name="naaya-mail-delivery") try: mailer.send(addr_from, [addr_to], message.as_string()) except AssertionError: mailer.send(addr_from, [addr_to], message) security.declareProtected(view, 'ask_for_password_reset') def ask_for_password_reset(self, REQUEST=None, email=None, on_create=False): """ view """ if REQUEST is None: REQUEST = self.REQUEST if not email: email = REQUEST.form['email'] agent = self._get_ldap_agent() users = agent.search_user_by_email(email) # , no_disabled=True) if users: # some people have multiple accounts; send mail for each account. for user_info in users: if user_info['status'] == 'disabled': msg = "This email: %s belongs to a disabled account" % \ user_info['email'] _set_session_message(REQUEST, 'error', msg) location = (self.absolute_url() + '/messages_html?msg=email-disabled') else: token = self._new_token(user_info['id']) log.info( "Sending password recovery email to user %r at %r.", user_info['id'], email) self._send_token_email(email, token, user_info) location = (self.absolute_url() + '/messages_html?msg=email-sent') else: log.info("Requested password recovery with invalid email %r.", email) msg = "Email address not found in database." _set_session_message(REQUEST, 'error', msg) location = self.absolute_url() + '/' if REQUEST and not on_create: REQUEST.RESPONSE.redirect(location) security.declareProtected(view, 'messages_html') def messages_html(self, REQUEST): """ view """ options = { 'message-name': REQUEST.form['msg'], } return self._render_template('zpt/pwreset_message.zpt', **options) def _say_token_expired(self, REQUEST): msg = ("Password reset link is invalid, perhaps it has " "expired. Please try again.") _set_session_message(REQUEST, 'error', msg) location = self.absolute_url() + '/' REQUEST.RESPONSE.redirect(location) def _expire_tokens(self): expired = [] cutoff_time = datetime.utcnow() - timedelta(days=1) for token, token_data in self._tokens.iteritems(): if token_data.timestamp < cutoff_time: expired.append(token) for token in expired: log.info('Token %r expired.', token) del self._tokens[token] security.declareProtected(view, 'confirm_email') def confirm_email(self, REQUEST): """ view """ token = REQUEST.form['token'] self._expire_tokens() token_data = self._tokens.get(token, None) if token_data is None: return self._say_token_expired(REQUEST) options = { 'token': token, 'user_id': token_data.user_id, } return self._render_template('zpt/pwreset_new_password.zpt', **options) def reset_password(self, REQUEST): """ view """ token = REQUEST.form['token'] self._expire_tokens() token_data = self._tokens.get(token, None) if token_data is None: return self._say_token_expired(REQUEST) new_password = REQUEST.form['password'] if new_password != REQUEST.form['password-confirm']: _set_session_message(REQUEST, 'error', "Passwords do not match.") location = self.absolute_url() + '/confirm_email?token=' + token else: log.info("Restting password for user %r with token %r", token_data.user_id, token) agent = self._get_ldap_agent(bind=True) try: agent.set_user_password(token_data.user_id, None, new_password) except CONSTRAINT_VIOLATION, e: if e.message['info'] in [ 'Password fails quality checking policy' ]: try: defaultppolicy = agent.conn.search_s( 'cn=defaultppolicy,ou=pwpolicies,o=EIONET,' 'l=Europe', SCOPE_BASE) p_length = defaultppolicy[0][1]['pwdMinLength'][0] message = '%s (min. %s characters)' % ( e.message['info'], p_length) except NO_SUCH_OBJECT: message = e.message['info'] else: message = e.message['info'] _set_session_message(REQUEST, 'error', message) location = (self.absolute_url() + '/confirm_email?token=' + token) else:
class Analysis(Persistent): """An Analysis object (and the referenced objects) stores all information the Ambrosia analysis found out. Attributes: * filename (str): the name of the APK * package (str): the package of the APK * start_time (datetime.datetime): when the ANANAS analysis started * end_time (datetime.datetime): when the ANANAS analysis ended * plugins (dict): the plugins (key) and wheter they were active during ANANAS analysis (value, bool) * hashes (dict): the hashes of the APK in the form {type: hash} Analysis also manages all (top-level) Events and Entities (see :class:`ambrosia_web.model.Event`, :class:`ambrosia_web.model.Entity`) and tries to optimize for searching performance. """ def __init__(self): self.filename = None self.package = None self.start_time = None self.end_time = None self._entities = PersistentMapping() """contains all entities in the form of (simplified): { class_name: ( [entitiy, ...], Binary tree of all entities (key: primary_identifier) ) } """ self._events = OOBTree.TreeSet() """contains all entities """ self._event_index = PersistentMapping() """contains indices for events in the form of { class_name: { key: Binary Tree { attribute_value: set(event, ...) } } } """ self.plugins = {} self.hashes = {} def add_entity(self, context, cls, *args): """Add an entity (alias for :func:`Analysis.get_entity`) """ self.get_entity(context, cls, *args) def iter_entities(self, context, cls): """iterate all known entities of a specific class. Args: context (ambrosia_web.context.AmbrosiaContext): the current context cls (class): the class of the entity we are looking for """ assert isinstance(context, ambrosia.context.AmbrosiaContext) assert issubclass(cls, Entity) if classname(cls) not in self._entities: return for entity in self._entities[classname(cls)][0]: yield entity def get_entity(self, context, cls, *args): """Search for a specific entity, if it does not exist, create a new one Args: context (ambrosia_web.context.AmbrosiaContext): the current context cls (class): the class of the entity we are looking for *args: the arguments that would construct an entity This method uses :func:`Entity.find` (of the specific entity class) to search for entities. This method receives a List of all known entitites of that class as well as a :class:`BTrees.OOBTree.BTree` also containing all entities (indexed by their *primary_identifier* to allow more efficient searching). Moreover this method relieves the \*args argument. The \*args argument contains all information that identifies a certain entity. This could be e.g. the IP address and the port of a server. Those values are passed to the find method. If the server is already known, the entity representing it is returned. If no such server entity exist a new one is created using those two parameters. This behaviour makes sure that multiple event referencing the same entity all have references to the exact same entity in memory. """ assert isinstance(context, ambrosia.context.AmbrosiaContext) assert issubclass(cls, Entity) if classname(cls) not in self._entities: # self.entities contains a tuple 1. with all emlements and 2. with an BTree over the primary identifier self._entities[classname(cls)] = (PersistentList(), OOBTree.BTree()) entity = self._entities[classname(cls)] res = cls.find(context, entity[0], entity[1], *args) if res is None: res = cls(context, *args) assert isinstance(res, Entity) entity[0].append(res) if res.primary_identifier not in entity[1]: entity[1][res.primary_identifier] = PersistentList() entity[1][res.primary_identifier].append(res) return res def iter_all_events(self, context, key=None, min_value=None, max_value=None, value=None): """Iterates over all event classes. Args: context (ambrosia_web.context.AmbrosiaContext): the current context key: the key we are searching for min_value: the minimum value max_value: the maximum value value: the specific value (to search for exactly one value) This method works just like :func:`Analysis.iter_events` but is not limited to a certain entity Type. Instead, it searches entitiy of all types. """ for class_name, idx in self._event_index.iteritems(): cls = get_class(class_name) assert issubclass(cls, Event) if key not in cls.indices: continue for evt in self.iter_events(context, cls, key, min_value, max_value, value): yield evt def iter_events(self, context, cls=None, key=None, min_value=None, max_value=None, value=None): """Iterates over all events matching specific conditions in an efficient manner. Args: context (ambrosia_web.context.AmbrosiaContext): the current context cls (class): the class of the events we are looking for key: the key we are searching for min_value: the minimum value max_value: the maximum value value: the specific value (to search for exactly one value) This method uses a internal indices to efficiently select specific events. Each event class defines attributes that should be indexed (:class:`Event`.indices). This class makes sure that those attributes can be searched for very fast. The method accepts the following combinations of argument: * nothing: return all events * *cls*: return all events of a specific class (inefficient) * *cls*, *key*, *min_value* and/or *max_value*: search for all events of a specific class where the attribute *key* is within the defined value constraints * *cls*, *key*, *value*: search all events of a specific class where the attribute *key* has the value *value* """ assert isinstance(context, ambrosia.context.AmbrosiaContext) assert cls is None or issubclass(cls, Event) assert isinstance(key, str) or key is None if key is None: # no key -> just get all elements for el in self._events: # if cls is given: filter by class if cls is None or isinstance(el, cls): yield el else: assert key in cls.indices, "key is not defined as index" if value is not None: # set min_value and max_value to value (if value is given) min_value, max_value = value, value class_name = classname(cls) # check if there is an index (there is none if no events of this class is known) if class_name in self._event_index and key in self._event_index[class_name]: # locate the index and use it for val, lst in self._event_index[class_name][key].iteritems(min_value, max_value): # the value the index refers to is a list since multiple events may have the same value for el in lst: yield el def _event_index_set(self, evt, key): """Locates the index for a specific event and key (and creates it if it does not exist) """ assert isinstance(key, str) assert isinstance(evt, Event) class_name = obj_classname(evt) if class_name not in self._event_index: self._event_index[class_name] = PersistentMapping() class_index = self._event_index[class_name] if key not in class_index: class_index[key] = OOBTree.BTree() key_index = class_index[key] key_val = getattr(evt, key) if key_val is None: return None ret = key_index.get(key_val) if ret is None: ret = OOBTree.OOTreeSet() key_index[key_val] = ret return ret def add_event(self, evt): """Add event and generate indices Args: evt (Event): the event to add .. warning:: The indexed attributes of an event may not be altered after the event has been added (otherwise the indices are out of date). This means that only static values may be indexed. """ assert isinstance(evt, Event) self._events.add(evt) for idx in getattr(evt.__class__, 'indices'): idxset = self._event_index_set(evt, idx) if idxset is not None: idxset.add(evt) def del_event(self, evt): """Delete event and update indices Args: evt (Event): the event to remove """ assert isinstance(evt, Event) try: self._events.remove(evt) except ValueError: # event does not exist, that's fine too return for idx in getattr(evt.__class__, 'indices'): idxset = self._event_index_set(evt, idx) if idxset is not None: idxset.remove(evt) def to_serializeable(self): """Returns all results in a serializable form """ for el in self._events: assert isinstance(el, Event) assert(el.start_ts > self.start_time) assert(el.start_ts < self.end_time) el.sort() events = list(self._events) events.sort(cmp=lambda x, y: x.cmp_by_time(y)) entities = {} for entity_class, class_entities in self._entities.iteritems(): for entity in class_entities[0]: assert isinstance(entity, Entity) entities[entity.primary_key] = entity.to_serializeable() return { 'start_time': js_date(self.start_time), 'end_time': js_date(self.end_time), 'filename': self.filename, 'package': self.package, 'events': [e.to_serializeable() for e in events], 'entities': entities } def adjust_times(self, context): """Goes through all events and calls adjust_times on all Events """ assert isinstance(context, ambrosia.context.AmbrosiaContext) for el in self._events: el.adjust_times(context)