diff --git a/src/gen/db/upgrade.py b/src/gen/db/upgrade.py index b166d16c2..85a769aed 100644 --- a/src/gen/db/upgrade.py +++ b/src/gen/db/upgrade.py @@ -21,26 +21,77 @@ # $Id$ from __future__ import with_statement -from gen.db import BSDDBTxn + """ -upgrade +methods to upgrade a database from version 13 to current version """ +from gen.db import BSDDBTxn +from gen.lib.nameorigintype import NameOriginType + + def gramps_upgrade_15(self): - """Upgrade database from version 14 to 15.""" - # This upgrade adds tagging + """Upgrade database from version 14 to 15. This upgrade adds: + * tagging + * surname list + """ length = len(self.person_map) self.set_total(length) # --------------------------------- # Modify Person # --------------------------------- - # Append the new tag field for handle in self.person_map.keys(): person = self.person_map[handle] - new_person = list(person) - new_person.append([]) - new_person = tuple(new_person) + (junk_handle, # 0 + gramps_id, # 1 + gender, # 2 + primary_name, # 3 + alternate_names, # 4 + death_ref_index, # 5 + birth_ref_index, # 6 + event_ref_list, # 7 + family_list, # 8 + parent_family_list, # 9 + media_list, # 10 + address_list, # 11 + attribute_list, # 12 + urls, # 13 + ord_list, # 14 + psource_list, # 15 + pnote_list, # 16 + change, # 17 + marker, # 18 + pprivate, # 19 + person_ref_list, # 20 + ) = person + + new_primary_name = convert_name_15(primary_name) + new_alternate_names = [convert_name_15(altname) for altname in + alternate_names] + new_person = (junk_handle, # 0 + gramps_id, # 1 + gender, # 2 + new_primary_name, # 3 + new_alternate_names,# 4 + death_ref_index, # 5 + birth_ref_index, # 6 + event_ref_list, # 7 + family_list, # 8 + parent_family_list, # 9 + media_list, # 10 + address_list, # 11 + attribute_list, # 12 + urls, # 13 + ord_list, # 14 + psource_list, # 15 + pnote_list, # 16 + change, # 17 + marker, # 18 + pprivate, # 19 + person_ref_list, # 20 + [] # 21, tags + ) with BSDDBTxn(self.env, self.person_map) as txn: txn.put(str(handle), new_person) self.update() @@ -49,6 +100,32 @@ def gramps_upgrade_15(self): with BSDDBTxn(self.env, self.metadata) as txn: txn.put('version', 15) +def convert_name_15(name): + (privacy, source_list, note_list, date, + first_name, surname, suffix, title, + name_type, prefix, patronymic, + group_as, sort_as, display_as, call) = name + + connector = u"" + origintype = (NameOriginType.NONE, u"") + patorigintype = (NameOriginType.PATRONYMIC, u"") + + if patronymic.strip() == u"": + #no patronymic, create a single surname + surname_list = [(surname, prefix, True, origintype, connector)] + else: + #a patronymic, if no surname or equal as patronymic, a single surname + if (surname.strip() == u"") or (surname == patronymic and prefix == u""): + surname_list = [(patronymic, prefix, True, patorigintype, connector)] + else: + #two surnames, first patronymic, then surname which is primary + surname_list = [(patronymic, u"", False, patorigintype, u""), + (surname, prefix, True, origintype, connector)] + + return (privacy, source_list, note_list, date, + first_name, surname_list, suffix, title, name_type, + group_as, sort_as, display_as, call) + def gramps_upgrade_14(self): """Upgrade database from version 13 to 14.""" # This upgrade modifies notes and dates diff --git a/src/gen/display/name.py b/src/gen/display/name.py index 2aca5c56f..3fc52f15d 100644 --- a/src/gen/display/name.py +++ b/src/gen/display/name.py @@ -23,6 +23,20 @@ """ Class handling language-specific displaying of names. + +Specific symbols for parts of a name are defined: + 't' : title + 'f' : given (first names) + 'l' : full surname (lastname) + 'c' : callname + 'x' : callname if existing, otherwise first first name (common name) + 'i' : initials of the first names + 'f' : patronymic surname (father) + 'o' : surnames without patronymic + 'm' : primary surname (main) + 'p' : list of all prefixes + 'q' : surnames without prefixes and connectors + 's' : suffix """ #------------------------------------------------------------------------- @@ -38,7 +52,7 @@ import re # GRAMPS modules # #------------------------------------------------------------------------- -from gen.lib import Name +from gen.lib import Name, NameOriginType try: import config @@ -52,17 +66,23 @@ except ImportError: # Constants # #------------------------------------------------------------------------- -_FIRSTNAME = 4 -_SURNAME = 5 -_SUFFIX = 6 -_TITLE = 7 -_TYPE = 8 -_PREFIX = 9 -_PATRONYM = 10 -_GROUP = 11 -_SORT = 12 -_DISPLAY = 13 -_CALL = 14 +_FIRSTNAME = 4 +_SURNAME_LIST = 5 +_SUFFIX = 6 +_TITLE = 7 +_TYPE = 8 +#_PREFIX = 9 +#_PATRONYM = 10 +_GROUP = 11 +_SORT = 12 +_DISPLAY = 13 +_CALL = 14 +_SURNAME_IN_LIST = 0 +_PREFIX_IN_LIST = 1 +_PRIMARY_IN_LIST = 2 +_TYPE_IN_LIST = 3 +_CONNECTOR_IN_LIST = 4 +_ORIGINPATRO = NameOriginType.PATRONYMIC _ACT = True _INA = False @@ -97,6 +117,63 @@ class NameDisplayError(Exception): def __str__(self): return self.value +#------------------------------------------------------------------------- +# +# Functions to extract data from raw lists (unserialized objects) +# +#------------------------------------------------------------------------- + +def _raw_full_surname(raw_surn_data_list): + """method for the 'l' symbol: full surnames""" + result = "" + for raw_surn_data in raw_surn_data_list: + result += "%s %s %s " % (raw_surn_data[_PREFIX_IN_LIST], + raw_surn_data[_SURNAME_IN_LIST], + raw_surn_data[_CONNECTOR_IN_LIST]) + return ' '.join(result.split()).strip() + +def _raw_primary_surname(raw_surn_data_list): + """method for the 'm' symbol: primary surname""" + for raw_surn_data in raw_surn_data_list: + if raw_surn_data[_PRIMARY_IN_LIST]: + result = "%s %s" % (raw_surn_data[_PREFIX_IN_LIST], + raw_surn_data[_SURNAME_IN_LIST]) + return ' '.join(result.split()) + return '' + +def _raw_patro_surname(raw_surn_data_list): + """method for the 'f' symbol: patronymic surname""" + for raw_surn_data in raw_surn_data_list: + if raw_surn_data[_TYPE_IN_LIST][0] == _ORIGINPATRO: + result = "%s %s" % (raw_surn_data[_PREFIX_IN_LIST], + raw_surn_data[_SURNAME_IN_LIST]) + return ' '.join(result.split()) + return '' + +def _raw_nonpatro_surname(raw_surn_data_list): + """method for the 'o' symbol: full surnames without patronymic""" + result = "" + for raw_surn_data in raw_surn_data_list: + if raw_surn_data[_TYPE_IN_LIST][0] != _ORIGINPATRO: + result += "%s %s %s " % (raw_surn_data[_PREFIX_IN_LIST], + raw_surn_data[_SURNAME_IN_LIST], + raw_surn_data[_CONNECTOR_IN_LIST]) + return ' '.join(result.split()).strip() + +def _raw_prefix_surname(raw_surn_data_list): + """method for the 'p' symbol: all prefixes""" + result = "" + for raw_surn_data in raw_surn_data_list: + result += "%s " % (raw_surn_data[_PREFIX_IN_LIST]) + return ' '.join(result.split()).strip() + +def _raw_single_surname(raw_surn_data_list): + """method for the 'q' symbol: surnames without prefix and connectors""" + result = "" + for raw_surn_data in raw_surn_data_list: + result += "%s " % (raw_surn_data[_SURNAME_IN_LIST]) + return ' '.join(result.split()).strip() + #------------------------------------------------------------------------- # # NameDisplay class @@ -112,10 +189,11 @@ class NameDisplay(object): STANDARD_FORMATS = [ (Name.DEF,_("Default format (defined by Gramps preferences)"),'',_ACT), - (Name.LNFN,_("Surname, Given Patronymic"),'%p %l, %f %y %s',_ACT), - (Name.FNLN,_("Given Surname"),'%f %y %p %l %s',_ACT), - (Name.PTFN,_("Patronymic, Given"),'%p %y, %s %f',_ACT), - (Name.FN,_("Given"),'%f',_ACT) + (Name.LNFN,_("Surname, Given"),'%p %l, %f %s',_ACT), + (Name.FN,_("Given"),'%f',_ACT), + (Name.FNLN,_("Given Surname"),'%f %p %l %s',_ACT), + # DEPRECATED FORMATS + (Name.PTFN,_("Patronymic, Given"),'%p %y, %s %f',_INA), ] def __init__(self): @@ -125,11 +203,12 @@ class NameDisplay(object): if WITH_GRAMPS_CONFIG: self.default_format = config.get('preferences.name-format') - if self.default_format == 0: + if self.default_format == 0 \ + or self.default_format not in Name.NAMEFORMATS : self.default_format = Name.LNFN config.set('preferences.name-format', self.default_format) else: - self.default_format = 1 + self.default_format = Name.LNFN self.set_default_format(self.default_format) @@ -138,28 +217,17 @@ class NameDisplay(object): def _format_raw_fn(self, fmt_str): return lambda x: self.format_str_raw(x, fmt_str) - + def _raw_lnfn(self, raw_data): - result = "%s %s, %s %s %s" % (raw_data[_PREFIX], - raw_data[_SURNAME], - raw_data[_FIRSTNAME], - raw_data[_PATRONYM], - raw_data[_SUFFIX]) + result = "%s, %s %s" % (_raw_full_surname(raw_data[_SURNAME_LIST]), + raw_data[_FIRSTNAME], + raw_data[_SUFFIX]) return ' '.join(result.split()) def _raw_fnln(self, raw_data): - result = "%s %s %s %s %s" % (raw_data[_FIRSTNAME], - raw_data[_PATRONYM], - raw_data[_PREFIX], - raw_data[_SURNAME], - raw_data[_SUFFIX]) - return ' '.join(result.split()) - - def _raw_ptfn(self, raw_data): - result = "%s %s, %s %s" % (raw_data[_PREFIX], - raw_data[_PATRONYM], - raw_data[_SUFFIX], - raw_data[_FIRSTNAME]) + result = "%s %s %s" % (raw_data[_FIRSTNAME], + _raw_full_surname(raw_data[_SURNAME_LIST]), + raw_data[_SUFFIX]) return ' '.join(result.split()) def _raw_fn(self, raw_data): @@ -170,7 +238,6 @@ class NameDisplay(object): raw_func_dict = { Name.LNFN : self._raw_lnfn, Name.FNLN : self._raw_fnln, - Name.PTFN : self._raw_ptfn, Name.FN : self._raw_fn, } @@ -279,31 +346,59 @@ class NameDisplay(object): The new function is of the form: def fn(raw_data): - return "%s %s %s %s %s" % (raw_data[_TITLE], + return "%s %s %s" % (raw_data[_TITLE], raw_data[_FIRSTNAME], - raw_data[_PREFIX], - raw_data[_SURNAME], raw_data[_SUFFIX]) + Specific symbols for parts of a name are defined: + 't' : title + 'f' : given (first names) + 'l' : full surname (lastname) + 'c' : callname + 'x' : callname if existing, otherwise first first name (common name) + 'i' : initials of the first names + 'f' : patronymic surname (father) + 'o' : surnames without patronymic + 'm' : primary surname (main) + 'p' : list of all prefixes + 'q' : surnames without prefixes and connectors + 's' : suffix + """ # we need the names of each of the variables or methods that are # called to fill in each format flag. # Dictionary is "code": ("expression", "keyword", "i18n-keyword") - d = {"t": ("raw_data[_TITLE]", "title", _("Person|title")), - "f": ("raw_data[_FIRSTNAME]", "given", _("given")), - "p": ("raw_data[_PREFIX]", "prefix", _("prefix")), - "l": ("raw_data[_SURNAME]", "surname", _("surname")), - "s": ("raw_data[_SUFFIX]", "suffix", _("suffix")), - "y": ("raw_data[_PATRONYM]", "patronymic", _("patronymic")), - "c": ("raw_data[_CALL]", "call", _("call")), + d = {"t": ("raw_data[_TITLE]", "title", + _("String replacement keyword Person|title")), + "f": ("raw_data[_FIRSTNAME]", "given", + _("String replacement keyword|given")), + "l": ("_raw_full_surname(raw_data[_SURNAME_LIST])", "surname", + _("String replacement keyword|surname")), + "s": ("raw_data[_SUFFIX]", "suffix", + _("String replacement keyword|suffix")), + "c": ("raw_data[_CALL]", "call", + _("String replacement keyword|call")), "x": ("(raw_data[_CALL] or raw_data[_FIRSTNAME].split(' ')[0])", - "common", - _("common")), + "common", + _("String replacement keyword|common")), "i": ("''.join([word[0] +'.' for word in ('. ' +" + " raw_data[_FIRSTNAME]).split()][1:])", - "initials", - _("initials")) + "initials", + _("String replacement keyword|initials")), + "f": ("_raw_patro_surname(raw_data[_SURNAME_LIST])", "patronymic", + _("String replacement keyword|patronymic")), + "o": ("_raw_nonpatro_surname(raw_data[_SURNAME_LIST])", "notpatronymic", + _("String replacement keyword|notpatronymic")), + "m": ("_raw_primary_surname(raw_data[_SURNAME_LIST])", + "primarysurname", + _("String replacement keyword|primarysurname")), + "p": ("_raw_prefix_surname(raw_data[_SURNAME_LIST])", + "prefix", + _("String replacement keyword|prefix")), + "q": ("_raw_single_surname(raw_data[_SURNAME_LIST])", + "rawsurnames", + _("String replacement keyword|rawsurnames")), } args = "raw_data" return self._make_fn(format_str, d, args) @@ -321,26 +416,54 @@ class NameDisplay(object): The new function is of the form: - def fn(first,surname,prefix,suffix,patronymic,title,call,): - return "%s %s %s %s %s" % (first,surname,prefix,suffix,patronymic) - + def fn(first, raw_surname_list, suffix, title, call,): + return "%s %s" % (first,suffix) + + Specific symbols for parts of a name are defined: + 't' : title + 'f' : given (first names) + 'l' : full surname (lastname) + 'c' : callname + 'x' : callname if existing, otherwise first first name (common name) + 'i' : initials of the first names + 'f' : patronymic surname (father) + 'o' : surnames without patronymic + 'm' : primary surname (main) + 'p' : list of all prefixes + 'q' : surnames without prefixes and connectors + 's' : suffix """ # we need the names of each of the variables or methods that are # called to fill in each format flag. # Dictionary is "code": ("expression", "keyword", "i18n-keyword") - d = {"t": ("title", "title", _("Person|title")), - "f": ("first", "given", _("given")), - "p": ("prefix", "prefix", _("prefix")), - "l": ("surname", "surname", _("surname")), - "s": ("suffix", "suffix", _("suffix")), - "y": ("patronymic", "patronymic", _("patronymic")), - "c": ("call", "call", _("call")), - "x": ("(call or first.split(' ')[0])", "common", _("common")), + d = {"t": ("title", "title", + _("String replacement keyword Person|title")), + "f": ("first", "given", + _("String replacement keyword|given")), + "l": ("_raw_full_surname(raw_surname_list)", "surname", + _("String replacement keyword|surname")), + "s": ("suffix", "suffix", + _("String replacement keyword|suffix")), + "c": ("call", "call", + _("String replacement keyword|call")), + "x": ("(call or first.split(' ')[0])", "common", + _("String replacement keyword|common")), "i": ("''.join([word[0] +'.' for word in ('. ' + first).split()][1:])", - "initials", _("initials")) + "initials", + _("String replacement keyword|initials")), + "f": ("_raw_patro_surname(raw_surname_list)", "patronymic", + _("String replacement keyword|patronymic")), + "o": ("_raw_nonpatro_surname(raw_surname_list)", "notpatro", + _("String replacement keyword|notpatro")), + "m": ("_raw_primary_surname(raw_surname_list)", "primary", + _("String replacement keyword name|primary")), + "p": ("_raw_prefix_surname(raw_surname_list)", "prefix", + _("String replacement keyword|prefix")), + "q": ("_raw_single_surname(raw_surname_list)", "rawlastnames", + _("String replacement keyword|rawlastnames")), } - args = "first,surname,prefix,suffix,patronymic,title,call" + args = "first,raw_surname_list,suffix,title,call" return self._make_fn(format_str, d, args) def _make_fn(self, format_str, d, args): @@ -410,7 +533,7 @@ class NameDisplay(object): # find each format flag in the original format string # for each one we find the variable name that is needed to - # replace it and add this to a list. This list will be used + # replace it and add this to a list. This list will be used to # generate the replacement tuple. # This compiled pattern should match all of the format codes. @@ -442,9 +565,9 @@ def fn(%s): return fn def format_str(self, name, format_str): - return self._format_str_base(name.first_name, name.surname, name.prefix, - name.suffix, name.patronymic, name.title, - name.call,format_str) + return self._format_str_base(name.first_name, name.surname_list, + name.suffix, name.title, + name.call, format_str) def format_str_raw(self, raw_data, format_str): """ @@ -463,22 +586,25 @@ def fn(%s): return ' '.join(s.split()) - def _format_str_base(self, first, surname, prefix, suffix, patronymic, - title, call, format_str): + def _format_str_base(self, first, surname_list, suffix, title, call, + format_str): """ Generates name from a format string. The following substitutions are made: - %t -> title - %f -> given (first name) - %p -> prefix - %s -> suffix - %l -> surname (last name) - %y -> patronymic - %c -> call - %x -> common - %i -> initials - The capital letters are substituted for capitalized name components. + '%t' : title + '%f' : given (first names) + '%l' : full surname (lastname) + '%c' : callname + '%x' : callname if existing, otherwise first first name (common name) + '%i' : initials of the first names + '%f' : patronymic surname (father) + '%o' : surnames without patronymic + '%m' : primary surname (main) + '%p' : list of all prefixes + '%q' : surnames without prefixes and connectors + '%s' : suffix + The capital letters are substituted for capitalized name components. The %% is substituted with the single % character. All the other characters in the fmt_str are unaffected. """ @@ -487,7 +613,8 @@ def fn(%s): func = self._gen_cooked_func(format_str) self.__class__.format_funcs[format_str] = func try: - s = func(first,surname,prefix,suffix,patronymic,title,call) + s = func(first, [surn.serialize() for surn in surname_list], + suffix, title, call) except (ValueError, TypeError,): raise NameDisplayError, "Incomplete format string" @@ -496,7 +623,8 @@ def fn(%s): #------------------------------------------------------------------------- def sort_string(self, name): - return u"%-25s%-30s%s" % (name.surname, name.first_name, name.suffix) + return u"%-25s%-30s%s" % (name.get_primary_surname, name.first_name, + name.suffix) def sorted(self, person): """ @@ -560,7 +688,7 @@ def fn(%s): def display_formal(self, person): """ Return a text string representing the L{gen.lib.Person} instance's - L{Name} in a manner that should be used for normal displaying. + L{Name} in a manner that should be used for formal displaying. @param person: L{gen.lib.Person} instance that contains the L{Name} that is to be displayed. The primary name is used for @@ -590,7 +718,7 @@ def fn(%s): return self.name_formats[num][_F_FN](name) def display_given(self, person): - return self.format_str(person.get_primary_name(),'%f %y') + return self.format_str(person.get_primary_name(),'%f') def name_grouping(self, db, person): return self.name_grouping_name(db, person.primary_name) @@ -599,22 +727,29 @@ def fn(%s): if pn.group_as: return pn.group_as sv = pn.sort_as - if sv == Name.LNFN or sv == Name.DEF: - return db.get_name_group_mapping(pn.surname) - elif sv == Name.PTFN: - return db.get_name_group_mapping(pn.patronymic) - else: + if sv == Name.DEF: + return db.get_name_group_mapping(pn.get_primary_surname()) + elif sv == Name.LNFN: + return db.get_name_group_mapping(pn.get_surname()) + elif sv == Name.FN: return db.get_name_group_mapping(pn.first_name) + else: + return db.get_name_group_mapping(pn.get_primary_surname()) def name_grouping_data(self, db, pn): if pn[_GROUP]: return pn[_GROUP] sv = pn[_SORT] - if sv == Name.LNFN or sv == Name.DEF: - return db.get_name_group_mapping(pn[_SURNAME]) - elif sv == Name.PTFN: - return db.get_name_group_mapping(pn[_PATRONYM]) - else: + if sv == Name.DEF: + return db.get_name_group_mapping(_raw_primary_surname( + pn[_SURNAME_LIST])) + elif sv == Name.LNFN: + return db.get_name_group_mapping(_raw_full_surname( + pn[_SURNAME_LIST])) + elif sv == Name.FN: return db.get_name_group_mapping(pn[_FIRSTNAME]) + else: + return db.get_name_group_mapping(_raw_primary_surname( + pn[_SURNAME_LIST])) displayer = NameDisplay() diff --git a/src/gen/lib/__init__.py b/src/gen/lib/__init__.py index f7b486e1b..dcbe78558 100644 --- a/src/gen/lib/__init__.py +++ b/src/gen/lib/__init__.py @@ -36,6 +36,7 @@ from gen.lib.mediaref import MediaRef from gen.lib.name import Name from gen.lib.reporef import RepoRef from gen.lib.srcref import SourceRef +from gen.lib.surname import Surname from gen.lib.url import Url from gen.lib.witness import Witness from gen.lib.childref import ChildRef @@ -68,6 +69,7 @@ from gen.lib.familyreltype import FamilyRelType from gen.lib.srcmediatype import SourceMediaType from gen.lib.eventroletype import EventRoleType from gen.lib.markertype import MarkerType +from gen.lib.nameorigintype import NameOriginType from gen.lib.notetype import NoteType from gen.lib.styledtexttagtype import StyledTextTagType diff --git a/src/gen/lib/name.py b/src/gen/lib/name.py index 10052aaa9..c103c8865 100644 --- a/src/gen/lib/name.py +++ b/src/gen/lib/name.py @@ -54,11 +54,12 @@ class Name(SecondaryObject, PrivacyBase, SurnameBase, SourceBase, NoteBase, """ DEF = 0 # Default format (determined by gramps-wide prefs) - LNF = 5 # last name first name + LNFN = 1 # last name first name FNLN = 2 # first name last name FN = 4 # first name + + NAMEFORMATS = (DEF, LNFN, FNLN, FN) #deprecated : - LNFN = 1 # last name first name [patronymic] PTFN = 3 # patronymic first name def __init__(self, source=None, data=None): diff --git a/src/gen/lib/surnamebase.py b/src/gen/lib/surnamebase.py index f92bf144a..7b570e9e9 100644 --- a/src/gen/lib/surnamebase.py +++ b/src/gen/lib/surnamebase.py @@ -121,9 +121,9 @@ class SurnameBase(object): """ self.surname_list = surname_list - def primary_surname(self): + def get_primary_surname(self): """ - Return the surname that is the primary surname + Return the string of the surname that is the primary surname :returns: Returns the surname instance that is the primary surname. If primary not set, and there is a surname, diff --git a/src/gui/dbloader.py b/src/gui/dbloader.py index b79c20f46..13aae5671 100644 --- a/src/gui/dbloader.py +++ b/src/gui/dbloader.py @@ -86,7 +86,14 @@ class DbLoader(CLIDbLoader): return 1 def _dberrordialog(self, msg): - DBErrorDialog(str(msg.value)) + import traceback + exc = traceback.format_exc() + try: + DBErrorDialog(str(msg.value)) + _LOG.error(str(msg.value)) + except: + DBErrorDialog(str(msg)) + _LOG.error(str(msg) +"\n" + exc) def _begin_progress(self): self.uistate.set_busy_cursor(1) @@ -312,8 +319,9 @@ class DbLoader(CLIDbLoader): except Errors.DbError, msg: self.dbstate.no_database() self._dberrordialog(msg) - except Exception: + except Exception as newerror: self.dbstate.no_database() + self._dberrordialog(str(newerror)) self._end_progress() return True diff --git a/src/gui/views/treemodels/peoplemodel.py b/src/gui/views/treemodels/peoplemodel.py index c346e9c94..08b628ac0 100644 --- a/src/gui/views/treemodels/peoplemodel.py +++ b/src/gui/views/treemodels/peoplemodel.py @@ -202,7 +202,7 @@ class PeopleBaseModel(object): def sort_name(self, data): n = Name() n.unserialize(data[COLUMN_NAME]) - return (n.get_surname(), n.get_first_name()) + return (n.get_primary_surname().get_surname(), n.get_first_name()) def column_name(self, data): handle = data[0] @@ -515,7 +515,6 @@ class PersonTreeModel(PeopleBaseModel, TreeBaseModel): data The object data. """ ngn = name_displayer.name_grouping_data - nsn = name_displayer.raw_sorted_name name_data = data[COLUMN_NAME] group_name = ngn(self.db, name_data)