Source code for indra.statements.context

import datetime


__all__ = ['Context', 'BioContext', 'WorldContext', 'RefContext', 'TimeContext',
           'MovementContext']


[docs]class Context(object): """An abstract class for Contexts.""" @classmethod def from_json(cls, jd): context_type = jd.get('type') if context_type == 'bio': return BioContext.from_json(jd) elif context_type == 'world': return WorldContext.from_json(jd) elif context_type == 'movement': return MovementContext.from_json(jd) else: raise ValueError('Unknown context type %s' % context_type)
[docs]class BioContext(Context): """An object representing the context of a Statement in biology. Parameters ---------- location : Optional[RefContext] Cellular location, typically a sub-cellular compartment. cell_line : Optional[RefContext] Cell line context, e.g., a specific cell line, like BT20. cell_type : Optional[RefContext] Cell type context, broader than a cell line, like macrophage. organ : Optional[RefContext] Organ context. disease : Optional[RefContext] Disease context. species : Optional[RefContext] Species context. """ def __init__(self, location=None, cell_line=None, cell_type=None, organ=None, disease=None, species=None): self.location = location self.cell_line = cell_line self.cell_type = cell_type self.organ = organ self.disease = disease self.species = species attrs = ['location', 'cell_line', 'cell_type', 'organ', 'disease', 'species'] def __eq__(self, other): return all([getattr(self, attr, None) == getattr(other, attr, None) for attr in self.attrs]) def __ne__(self, other): return not self.__eq__(other) def __bool__(self): return any([getattr(self, attr, None) is not None for attr in self.attrs]) def __nonzero__(self): return self.__bool__() @classmethod def from_json(cls, jd): # For all the attributes, we deserialize them if they have a value, # and make a dict that can be passed to the constructor ref_contexts = {attr: (RefContext.from_json(jd.get(attr)) if jd.get(attr) else None) for attr in cls.attrs} bs = cls(**ref_contexts) return bs def to_json(self): jd = {attr: getattr(self, attr).to_json() for attr in self.attrs if getattr(self, attr, None) is not None} jd['type'] = 'bio' return jd def __str__(self): pieces = ['%s=%s' % (attr, getattr(self, attr)) for attr in self.attrs if getattr(self, attr, None) is not None] args = ', '.join(pieces) return 'BioContext(%s)' % args def __repr__(self): return self.__str__()
[docs]class WorldContext(Context): """An object representing the context of a Statement in time and space. Parameters ---------- time : Optional[TimeContext] A TimeContext object representing the temporal context of the Statement. geo_location : Optional[RefContext] The geographical location context represented as a RefContext """ def __init__(self, time=None, geo_location=None): self.time = time self.geo_location = geo_location def __eq__(self, other): return (self.time == other.time) and \ (self.geo_location == other.geo_location) def __ne__(self, other): return not self.__eq__(other) def __bool__(self): return self.time is not None or self.geo_location is not None def __nonzero__(self): return self.__bool__() @classmethod def from_json(cls, jd): time_entry = jd.get('time') time = TimeContext.from_json(time_entry) if time_entry else None geo_entry = jd.get('geo_location') geo_location = RefContext.from_json(geo_entry) if geo_entry else None return cls(time=time, geo_location=geo_location) def to_json(self): jd = {'type': 'world', 'time': self.time.to_json() if self.time else None, 'geo_location': (self.geo_location.to_json() if self.geo_location else None)} return jd def __str__(self): pieces = [] if self.time: pieces.append('time=%s' % self.time) if self.geo_location: pieces.append('geo_location=%s' % self.geo_location) args = ', '.join(pieces) return 'WorldContext(%s)' % args def __repr__(self): return self.__str__()
[docs]class RefContext(object): """An object representing a context with a name and references. Parameters ---------- name : Optional[str] The name of the given context. In some cases a text name will not be available so this is an optional parameter with the default being None. db_refs : Optional[dict] A dictionary where each key is a namespace and each value is an identifier in that namespace, similar to the db_refs associated with Concepts/Agents. """ def __init__(self, name=None, db_refs=None): self.name = name self.db_refs = {} if db_refs is None else db_refs def __eq__(self, other): return (self.name == other.name) and \ (self.db_refs == other.db_refs) def __ne__(self, other): return not self.__eq__(other) def to_json(self): jd = {'name': self.name, 'db_refs': self.db_refs} return jd @classmethod def from_json(cls, jd): rc = cls(name=jd.get('name'), db_refs=jd.get('db_refs')) return rc def __str__(self): pieces = [] if self.name: pieces.append('name="%s"' % self.name) if self.db_refs: pieces.append('db_refs=%s' % self.db_refs) args = ', '.join(pieces) return 'RefContext(%s)' % args def __repr__(self): return self.__str__()
[docs]class TimeContext(object): """An object representing the time context of a Statement Parameters ---------- text : Optional[str] A string representation of the time constraint, typically as seen in text. start : Optional[datetime] A `datetime` object representing the start time end : Optional[datetime] A `datetime` object representing the end time duration : int The duration of the time constraint in seconds """ def __init__(self, text=None, start=None, end=None, duration=None): self.text = text self.start = start self.end = end self.duration = duration def refinement_of(self, other): # If both starts are given if self.start and other.start: # If this started earlier, it can't be a refinement if self.start <= other.start: return False # If it ended later, it can't be a refinement elif self.end and other.end: if self.end >= other.end: return False # If the other end is not given, it's a refinement elif self.end and not other.end: return True # If neither end is given, it's also a refinement at this point return True # If we have a start time and other doesn't, it's a refinement elif self.start and not other.start: return True # Otherwise it's not a refinement return False def __eq__(self, other): return (self.text == other.text) and \ (self.start == other.start) and \ (self.end == other.end) and \ (self.duration == other.duration) def __ne__(self, other): return not self.__eq__(other) def to_json(self): def date_to_str(date): if date is None: return None else: return date.strftime('%Y-%m-%dT%H:%M') jd = {'text': self.text, 'start': date_to_str(self.start), 'end': date_to_str(self.end)} if self.duration is not None: jd['duration'] = self.duration return jd @classmethod def from_json(cls, jd): def date_from_str(date_str): if not date_str: return None try: dt = datetime.datetime.strptime(date_str, '%Y-%m-%dT%H:%M') except Exception as e: return None return dt tc = cls(text=jd.get('text'), start=date_from_str(jd.get('start')), end=date_from_str(jd.get('end')), duration=jd.get('duration')) return tc def __str__(self): pieces = [] if self.text: pieces.append('text="%s"' % self.text) if self.start: pieces.append('start=%s' % self.start) if self.end: pieces.append('end=%s' % self.end) if self.duration: pieces.append('duration=%s' % self.duration) args = ', '.join(pieces) return 'TimeContext(%s)' % args def __repr__(self): return self.__str__()
[docs]class MovementContext(Context): """An object representing the context of a movement between start and end points in time. Parameters ---------- locations : Optional[list[dict] A list of dictionaries each containing a RefContext object representing geographical location context and its role (e.g. 'origin', 'destination', etc.) time : Optional[TimeContext] A TimeContext object representing the temporal context of the Statement. """ def __init__(self, locations=None, time=None): self.locations = locations if locations else [] self.time = time def __eq__(self, other): return (self.locations == other.locations) and \ (self.time == other.time) def __ne__(self, other): return not self.__eq__(other) def __bool__(self): return self.locations is not None or self.time is not None def __nonzero__(self): return self.__bool__() @classmethod def from_json(cls, jd): locations_entry = jd.get('locations') if locations_entry: locations = [ {'location': RefContext.from_json(location['location']), 'role': location['role']} for location in locations_entry] else: locations = None time_entry = jd.get('time') if time_entry: time = TimeContext.from_json(time_entry) else: time = None return cls(locations=locations, time=time) def to_json(self): if self.locations: locations_json = [ {'location': location['location'].to_json(), 'role': location['role']} for location in self.locations] else: locations_json = [] jd = {'type': 'movement', 'locations': locations_json, 'time': self.time.to_json() if self.time else None} return jd def __str__(self): pieces = [] if self.locations: locs = [] for location in self.locations: locs.append('%s(%s)' % (location['location'], location['role'])) locations = ', '.join(locs) pieces.append('locations=%s' % locations) if self.time: pieces.append('time=%s' % self.time) args = ', '.join(pieces) return 'MovementContext(%s)' % args def __repr__(self): return self.__str__()