def alive(person): """Whether the person is alive""" # If we have no birth date, we could assume it is at least 15 years # before the first child's birth date (recursively). But that becomes # more expensive to compute return not person.death \ and (not person.birth or DateRange.today().years_since(person.birth.Date) <= max_age)
def default (self, obj): """See inherited documentation""" if isinstance (obj, models.Persona): b = self._event (obj.birth) d = self._event (obj.death) if not year_only and obj.birth: if obj.death: if obj.death.Date: age = " (age " \ + str (obj.death.Date.years_since (obj.birth.Date)) \ + ")" d[0] += age else: age = " (age " \ + str (DateRange.today().years_since (obj.birth.Date)) \ + ")" d = [age, None, None] return {"id":obj.id, "givn":obj.given_name, 'surn':obj.surname, 'sex':obj.sex, 'generation': obj.generation, 'y':obj.styles, 'b':b, 'd':d} elif isinstance (obj, DateRange): return obj.display(year_only=year_only) elif isinstance (obj, models.Event): return self._event (obj) elif isinstance(obj, set): return list(obj) elif hasattr(obj, 'to_json'): return obj.to_json() return super (ModelEncoder, self).default(obj)
def alive(person): """Whether the person is alive""" # If we have no birth date, we could assume it is at least 15 years # before the first child's birth date (recursively). But that becomes # more expensive to compute logger.error('Did not compute birth or death for person') return False if person.death is not None: return False elif person.birth is None: # Might be alive. We could look at other events to guess at the # timeframe return True else: d = DateRange.today().years_since(person.birth.Date) if d is None: # Could not compute elapsed time (likely because birth has no know # year return True else: return d <= max_age
def __init__(self, rules, graph, decujus): """Rules specifies the rules to use for the highlighting. """ super(Styles, self).__init__() # Preprocess the rules for faster computation self.graph = graph self.rules = [] self.today = DateRange.today() self.counts = [None] * len(rules) # the "count" rules: (test, value) self._need_place_parts = False self.styles_count = 0 for index, r in enumerate(rules): rule_name, rule_type, rule_tests, rule_style = r if rule_type in (RULE_EVENT, RULE_ATTR): tests = [] for t in rule_tests: if t[0] == "count" and rule_type == RULE_EVENT: # Handled separately at the end self.counts[index] = (rules_func[t[1]], t[2]) continue elif t[0] == "ancestor" and rule_type == RULE_ATTR: ancestors = graph.people_in_tree( id=t[2], maxdepthAncestors=-1, maxdepthDescendants=0) tests.append((t[0], [a.main_id for a in ancestors])) continue elif t[0] == "descendant" and rule_type == RULE_ATTR: descendants = graph.people_in_tree( id=t[2], maxdepthAncestors=0, maxdepthDescendants=-1) tests.append((t[0], [a.main_id for a in descendants])) continue elif t[0] == "IMPLEX" and rule_type == RULE_ATTR: # ??? We used to preprocess the tree to know how many times # an id occurred in the tree, but the graph no longer # provides that info def build_implex(counts, id): counts[id] = counts.get(id, 0) + 1 fathers = graph.fathers(id) if fathers: build_implex(counts, fathers[0].main_id) mothers = graph.mothers(id) if mothers: build_implex(counts, mothers[0].main_id) counts = dict() build_implex( counts, graph.node_from_id(decujus).main_id) tests.append((t[0], rules_func[t[1]], t[2], counts)) continue elif t[0].startswith("place.") and t[0] != "place.name": self._need_place_parts = True if t[1] == RULE_CONTAINS_INSENSITIVE \ or t[1] == RULE_CONTAINS_NOT_INSENSITIVE \ or t[1] == RULE_IS_INSENSITIVE: tests.append((t[0], rules_func[t[1]], t[2].lower())) elif t[1] == RULE_BEFORE: tests.append((t[0], rules_func[t[1]], DateRange(t[2]))) else: tests.append((t[0], rules_func[t[1]], t[2])) self.rules.append((rule_type, tests, rule_style)) else: print "Unknown rule tag in the style rules: %s" % r self.no_match = [0] * len(self.rules)
def __init__(self, rules, graph, decujus): """Rules specifies the rules to use for the highlighting. """ super(Styles, self).__init__() # Preprocess the rules for faster computation self.graph = graph self.rules = [] self.today = DateRange.today() self.counts = [None] * len(rules) # the "count" rules: (test, value) self._need_place_parts = False self.styles_count = 0 for index, r in enumerate(rules): rule_name, rule_type, rule_tests, rule_style = r if rule_type in (RULE_EVENT, RULE_ATTR): tests = [] for t in rule_tests: if t[0] == "count" and rule_type == RULE_EVENT: # Handled separately at the end self.counts[index] = (rules_func[t[1]], t[2]) continue elif t[0] == "ancestor" and rule_type == RULE_ATTR: ancestors = graph.people_in_tree(id=t[2], maxdepthAncestors=-1, maxdepthDescendants=0) tests.append((t[0], [a.main_id for a in ancestors])) continue elif t[0] == "descendant" and rule_type == RULE_ATTR: descendants = graph.people_in_tree( id=t[2], maxdepthAncestors=0, maxdepthDescendants=-1) tests.append((t[0], [a.main_id for a in descendants])) continue elif t[0] == "IMPLEX" and rule_type == RULE_ATTR: # ??? We used to preprocess the tree to know how many times # an id occurred in the tree, but the graph no longer # provides that info def build_implex(counts, id): counts[id] = counts.get(id, 0) + 1 fathers = graph.fathers(id) if fathers: build_implex(counts, fathers[0].main_id) mothers = graph.mothers(id) if mothers: build_implex(counts, mothers[0].main_id) counts = dict() build_implex(counts, graph.node_from_id(decujus).main_id) tests.append((t[0], rules_func[t[1]], t[2], counts)) continue elif t[0].startswith("place.") and t[0] != "place.name": self._need_place_parts = True if t[1] == RULE_CONTAINS_INSENSITIVE \ or t[1] == RULE_CONTAINS_NOT_INSENSITIVE \ or t[1] == RULE_IS_INSENSITIVE: tests.append((t[0], rules_func[t[1]], t[2].lower())) elif t[1] == RULE_BEFORE: tests.append((t[0], rules_func[t[1]], DateRange(t[2]))) else: tests.append((t[0], rules_func[t[1]], t[2])) self.rules.append((rule_type, tests, rule_style)) else: print "Unknown rule tag in the style rules: %s" % r self.no_match = [0] * len(self.rules)
def __get_events(nodes, styles, graph, types=None, schemes=None, query_groups=True): """Compute the events for the various persons in IDS (all all persons in the database if None) :param nodes: A set of graph.Persona_node, or None to get all persons from the database. :param graph: an instance of Graph, which is used to compute whether two ids represent the same person. :return: a list of persons: * persons is a dictionary of Persona instances, indexed on persona_id SCHEMES is the list of ids of Surety_Scheme that are used. You should pass a set() if you are interested in this. Otherwise, it is just discarded. This sets persons[*].chars to a list of the characteristics. Only the events of type in TYPES are returned """ if nodes: ids = [a.main_id for a in nodes] else: ids = None compute_parts = styles and styles.need_place_parts() roles = dict() # role_id -> name places = dict() # place_id -> place assert (schemes is None or isinstance(schemes, set)) # Get the role names for role in models.Event_Type_Role.objects.all(): roles[role.id] = role.name ############## # Create the personas that will be returned. ############## persons = dict() # id -> person if ids: for p in sql_in(models.Persona.objects, "id", ids): # p.id is always the main_id, since that's how ids was built persons[p.id] = p __add_default_person_attributes(p) else: for p in models.Persona.objects.all(): mid = graph.node_from_id(p.id).main_id if mid not in persons: persons[mid] = p __add_default_person_attributes(p) ################ # Check all events that the persons were involved in. ################ events = models.P2E.objects.select_related('event', 'event__place', 'event__type', 'surety') if types: events = events.filter(event__type__in=types) all_ids = None if nodes: all_ids = set() for p in nodes: all_ids.update(p.ids) all_events = dict() # All query the 'principal' for each events, so that we can provide # that information graphically. for p in sql_in(events, "person", all_ids): # or_q=Q(role=models.Event_Type_Role.principal)): e = p.event p_node = graph.node_from_id(p.person_id) person = persons[p_node.main_id] person.all_events[e.id] = EventInfo(event=e, role=roles[p.role_id], assertion=p) e.sources = getattr(e, "sources", set()) e.sources.add(p.source_id) e.Date = e.date and DateRange(e.date) if schemes is not None: schemes.add(p.surety.scheme_id) if compute_parts and e.place: places[e.place_id] = e.place if styles: styles.process(person, p.role_id, e) if not p.disproved \ and p.role_id == models.Event_Type_Role.principal: if not e.Date: pass elif e.type_id == models.Event_Type.birth: if person.birth is None \ or person.birth.date_sort > e.date_sort: person.birth = e elif e.type_id == models.Event_Type.death: if person.death is None \ or person.death.date_sort < e.date_sort: person.death = e elif e.type_id == models.Event_Type.marriage: person.marriage = e ######### # Get all groups to which the personas belong ######### if query_groups: groups = models.P2G.objects.select_related('group') for gr in sql_in(groups, "person", all_ids): p_node = graph.node_from_id(gr.person_id) person = persons[p_node.main_id] person.all_groups[gr.group_id] = GroupInfo(group=gr.group, assertion=gr) if gr.source_id: src = getattr(gr.group, "sources", []) src.append(gr.source_id) gr.group.sources = src gr.group.role = gr.role if schemes is not None: schemes.add(gr.surety.scheme_id) ######### # Get all characteristics of these personas ######### p2c = dict() # characteristic_id -> person all_p2c = models.P2C.objects.select_related('characteristic', 'characteristic__place') for p in sql_in(all_p2c, "person", all_ids): c = p.characteristic p_node = graph.node_from_id(p.person_id) person = persons[p_node.main_id] p2c[c.id] = person c.sources = getattr(c, "sources", set()) c.sources.add(p.source_id) c.date = c.date and DateRange(c.date) if schemes is not None: schemes.add(p.surety.scheme_id) person.all_chars[c.id] = CharInfo(char=c, assertion=p, parts=[]) if compute_parts and c.place: places[c.place_id] = c.place chars = models.Characteristic_Part.objects.select_related( 'type', 'characteristic', 'characteristic__place') for part in sql_in(chars, "characteristic", nodes and p2c.keys()): person = p2c[part.characteristic_id] ch = person.all_chars[part.characteristic_id] ch.parts.append(CharPartInfo(name=part.type.name, value=part.name)) if part.type_id == models.Characteristic_Part_Type.sex: person.sex = part.name elif part.type_id == models.Characteristic_Part_Type.given_name: person.given_name = part.name elif part.type_id == models.Characteristic_Part_Type.surname: person.surname = part.name ######## # Compute place parts once, to limit the number of queries # These are only used for styles, not for actual display, although we # could benefit from them. ######## if compute_parts: prev_place = None d = None for p in sql_in( models.Place_Part.objects.order_by('place').select_related( 'type'), "place", places.keys()): # ??? We should also check the parent place to gets its own parts if p.place_id != prev_place: prev_place = p.place_id d = dict() setattr(places[prev_place], "parts", d) d[p.type.name] = p.name return persons
def default(self, obj): """See inherited documentation""" if self.custom: p = self.custom(obj) if p: return p if isinstance(obj, DateRange): return obj.display(year_only=self.year_only) elif isinstance(obj, datetime.datetime): return obj.isoformat() elif isinstance(obj, django.db.models.query.QuerySet): return list(obj) elif isinstance(obj, GroupInfo): return dict(group=obj.group, assertion=obj.assertion) elif isinstance(obj, CharInfo): return dict(char=obj.char, parts=obj.parts, assertion=obj.assertion) elif isinstance(obj, CharPartInfo): return dict(name=obj.name, value=obj.value) elif isinstance(obj, models.Characteristic): return dict( name=obj.name, sources=list(obj.sources if hasattr(obj, 'sources') else []), date=obj.date, date_sort=obj.date_sort, place=obj.place) elif isinstance(obj, models.Assertion): result = dict(disproved=obj.disproved, rationale=obj.rationale, surety=obj.surety_id) if isinstance(obj, models.P2P): result['person1'] = obj.person1 result['person2'] = obj.person2 elif isinstance(obj, models.P2E): result['date'] = obj.event.date and DateRange(obj.event.date) result['place'] = obj.event.place and obj.event.place.name result['person1'] = obj.person result['event2'] = (obj.event, obj.role.name) elif isinstance(obj, models.P2C): parts = [] for p in models.Characteristic_Part.objects.filter( characteristic=obj.characteristic).select_related(): parts.append((p.type.name, p.name)) result['date'] = \ obj.characteristic.date and DateRange(obj.characteristic.date) result['place'] = \ obj.characteristic.place and obj.characteristic.place.name result['person1'] = obj.person result['char2'] = (obj.characteristic, parts) return result elif isinstance(obj, models.Source): return dict(higher_source_id=obj.higher_source_id, subject_place=obj.subject_place, jurisdiction_place=obj.jurisdiction_place, researcher=obj.researcher, subject_date=obj.subject_date, medium=obj.medium, title=obj.title, abbrev=obj.abbrev, biblio=obj.biblio, last_change=obj.last_change, comments=obj.comments) elif isinstance(obj, EventInfo): return dict(event=obj.event, role=obj.role, assertion=obj.assertion) elif isinstance(obj, models.Event): return dict( id=obj.id, name=obj.name, type=obj.type, place=obj.place, sources=list(obj.sources if hasattr(obj, 'sources') else []), date=obj.date, date_sort=obj.date_sort) elif isinstance(obj, set): return list(obj) elif hasattr(obj, 'to_json'): return obj.to_json() else: return super(ModelEncoder, self).default(obj)