ERROR: _reportdialog.py: line 801: Failed to run report

I receive an exception when use Narrated web site export.

45894547: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 535, in write_report
    self.tab["Person"].display_pages(the_lang, the_title)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 178, in display_pages
    self.individualpage(self.report, the_lang, the_title, person)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 682, in individualpage
    individualdetail += self.display_ind_associations(assocs)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 1592, in display_ind_associations
    person_lnk = self.new_person_link(person_ref.ref, uplink=True)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/basepage.py", line 3055, in new_person_link
    (link, name, gid) = result
ValueError: not enough values to unpack (expected 3, got 0)

I see something similar discussion here Narrated Web Site report error

But looks like it was already fixed in 5.2 version Use imagesize rather than magic by Nick-Hall · Pull Request #1597 · gramps-project/gramps · GitHub

My Gramps is 5.2.1.

GRAMPS: 5.2.1 
Python: 3.10.12 
BSDDB: 6.2.9 (5, 3, 28) 
sqlite: 3.37.2 (2.6.0)
LANG: en_US.UTF-8
OS: Linux
Distribution: 6.8.0-45-generic

And also I have installed recommended package:

pip show imagesize
Name: imagesize
Version: 1.4.1
Summary: Getting image size from png/jpeg/jpeg2000/gif file
Home-page: https://github.com/shibukawa/imagesize_py
Author: Yoshiki Shibukawa
Author-email: yoshiki@shibu.jp
License: MIT
Location: /home/yurii/.local/lib/python3.10/site-packages
Requires: 
Required-by: 

What is wrong? Thanks

A bit more logs which I added here:

    def new_person_link(
        self, person_handle, uplink=False, person=None, name_style=_NAME_STYLE_DEFAULT
    ):
        """
        creates a link for a person. If a page is generated for the person, a
        hyperlink is created, else just the name of the person. The returned
        vale will be an Html object if a hyperlink is generated, otherwise
        just a string

        @param: person_handle -- Person in database
        @param: uplink        -- If True, then "../../../" is inserted in
                                 front of the result
        @param: person        -- Person object. This does not need to be
                                 passed. It should be passed if the person
                                 object has already been retrieved, as it
                                 will be used to improve performance
        """
        result = self.report.obj_dict.get(Person).get(person_handle)
        print(f"Debug: person_handle = {person_handle}, result = {result}")
        person = self.r_db.get_person_from_handle(person_handle)
        if person:
            gramps_id = person.get_gramps_id()
            print(f"Gramps ID for person_handle {person_handle}: {gramps_id}")
        else:
            print(f"Person with handle {person_handle} not found.")

The logs:

Debug: person_handle = f47f6080833755be8c3abffc89c, result = ('ppl/c/9/f47f6080833755be8c3abffc89c.html', 'Сергієнко, Серафима Порфирівна', 'I1738')
Gramps ID for person_handle f47f6080833755be8c3abffc89c: I1738
Debug: person_handle = f6a90d766ee49515d7b8abf0c33, result = set()
Person with handle f6a90d766ee49515d7b8abf0c33 not found.
2024-10-12 23:21:39.696: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 535, in write_report
    self.tab["Person"].display_pages(the_lang, the_title)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 178, in display_pages
    self.individualpage(self.report, the_lang, the_title, person)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 682, in individualpage
    individualdetail += self.display_ind_associations(assocs)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 1592, in display_ind_associations
    person_lnk = self.new_person_link(person_ref.ref, uplink=True)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/basepage.py", line 3062, in new_person_link
    (link, name, gid) = result
ValueError: not enough values to unpack (expected 3, got 0)

How is it possible? Wrong handle?

Person with handle f6a90d766ee49515d7b8abf0c33 not found.

It is possible that the person with that handle exists in the database, but is filtered out by a proxy database. In this case the get_person_from_handle method would return None. If the handle didn’t exist we would expect a HandleError exception to be raised instead.

1 Like

does anybody know how can I fix this in a correct way, not a hack in the export code?

This is very strange. I made export to gramps xml, and found this hande:

<person handle="_f6a90d766ee49515d7b8abf0c33" change="1728636995" id="I4477">

This person is opening good, it is existing in the DB.

Thank you for trying with debug. It shows that if the person’s not found, for a reason like mentioned by Nick, the result is an empty set, indicated by set(), and not None. And as you can see two lines above that, the normal contents of that set consist of an html link, for the site, a name, and a Gramps ID.

The ValueError indicates that the code does not expect an empty set, hence the message that it expected 3. And that’s understandable, because it’s in the else part of an if that tests result against None.

This is a bug that can be solved by expanding the test of result against None with a test for an empty set. And that’s at this line in the code:

The code can be fixed by testing the set as described here:

And I bet that access to the person is blocked by a privacy filter, hidden behind the proxy that Nick wrote about.

P.S. I haven’t done any coding for 5.2, so there may be other solutions, like letting the proxy return None. I’m just trying to analyze, and don’t pretend to have the best solution for this.

1 Like

I fixed it there:

        # construct link, name and gid
        if result is None or (isinstance(result, set) and not result) or len(result) != 3:
            # The person is not included in the webreport
            link = ""
            if person is None:
                person = self.r_db.get_person_from_handle(person_handle)
            if person:
                name = self.report.get_person_name(person)
                gid = person.get_gramps_id()
            else:
                name = self._("Unknown")
                gid = ""

I changed:

if result is None:

To:

if result is None or (isinstance(result, set) and not result) or len(result) != 3:

But another exception in another script occurs:

2024-10-13 00:11:56.558: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 535, in write_report
    self.tab["Person"].display_pages(the_lang, the_title)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 178, in display_pages
    self.individualpage(self.report, the_lang, the_title, person)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 533, in individualpage
    BasePage.__init__(self, report, the_lang, the_title, person.get_gramps_id())
AttributeError: 'NoneType' object has no attribute 'get_gramps_id'

Looks like the same

The second error is also fixed with additional condition here:

    #################################################
    #
    #    creates an Individual Page
    #
    #################################################
    def individualpage(self, report, the_lang, the_title, person):
        
        if person is None:
            return
        
        """

But I still have errors:

2024-10-13 00:22:14.125: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 535, in write_report
    self.tab["Person"].display_pages(the_lang, the_title)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 180, in display_pages
    self.individuallistpage(
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 387, in individuallistpage
    surname = get_surname_from_person(self.r_db, person)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/common.py", line 468, in get_surname_from_person
    primary_name = person.get_primary_name()
AttributeError: 'NoneType' object has no attribute 'get_primary_name'

Fixed the third one with additional condition:

def get_surname_from_person(dbase, person):

    if person is None:
        return ""

    """
    get the person's surname
    get the primary name
    if group as get the group_as surname
    else get the primary surname of the primary name
         and correct for [global] group_as name
    correct for surnames that are space or None
    """
    primary_name = person.get_primary_name()

But one more:

2024-10-13 00:29:12.202: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 535, in write_report
    self.tab["Person"].display_pages(the_lang, the_title)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 180, in display_pages
    self.individuallistpage(
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 486, in individuallistpage
    for person_handle in sorted(
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/basepage.py", line 262, in sort_on_name_and_grampsid
    name = _nd.display(person)
  File "/usr/local/lib/python3.10/dist-packages/gramps/gen/display/name.py", line 1042, in display
    name = person.get_primary_name()
AttributeError: 'NoneType' object has no attribute 'get_primary_name'

Fixed bug 4:

    def display(self, person):

        if person is None:
            return ""

        """
        Return a text string representing the :class:`~.person.Person`
        instance's :class:`~.name.Name` in a manner that should be used for
        normal displaying.

        :param person: :class:`~.person.Person` instance that contains the
                       :class:`~.name.Name` that is to be displayed. The
                       primary name is used for the display.
        :type person: :class:`~.person.Person`
        :returns: Returns the :class:`~.person.Person` instance's name
        :rtype: str
        """
        name = person.get_primary_name()
        return self.display_name(name)

And issue 5 :joy:

2024-10-13 00:34:53.386: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 535, in write_report
    self.tab["Person"].display_pages(the_lang, the_title)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 180, in display_pages
    self.individuallistpage(
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/person.py", line 486, in individuallistpage
    for person_handle in sorted(
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/basepage.py", line 263, in sort_on_name_and_grampsid
    return (name, person.get_gramps_id())
AttributeError: 'NoneType' object has no attribute 'get_gramps_id'

Place 5 is fixed with adding additional valid_handle_list in person.py:

                        first_surname = True
                        first_individual = True

                        valid_handle_list = [
                            person_handle for person_handle in handle_list 
                            if self.r_db.get_person_from_handle(person_handle) is not None
                        ]

                        for person_handle in sorted(
                            valid_handle_list, key=self.sort_on_name_and_grampsid
                        ):
                            (
                                date,
                                first_surname,
                                first_individual,
                            ) = self.__output_person(
                                date,
                                tbody,
                                bucket_letter,
                                bucket_link,
                                showbirth,
                                showdeath,
                                showpartner,
                                showparents,
                                surname,
                                surnamed,
                                first_surname,
                                first_individual,
                                person_handle,
                            )

Error 6:

2024-10-13 00:50:19.748: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 537, in write_report
    self.build_gendex(self.obj_dict[Person], the_lang)
  File "/usr/local/lib/python3.10/dist-packages/gramps/plugins/webreport/narrativeweb.py", line 1322, in build_gendex
    datex = person.get_change_time()
AttributeError: 'NoneType' object has no attribute 'get_change_time'

fixed:

    def build_gendex(self, ind_list, the_lang):
        """
        Create a gendex file

        @param: ind_list -- The list of person to use
        @param: the_lang -- The lang to process
        """
        if self.inc_gendex:
            message = _("Creating GENDEX file")
            pgr_title = self.pgrs_title(the_lang)
            with self.user.progress(pgr_title, message, len(ind_list)) as step:
                fp_gendex, gendex_io = self.create_file("gendex", ext=".txt")
                date = 0
                index = 1
                for person_handle in ind_list:
                    step()
                    index += 1
                    person = self._db.get_person_from_handle(person_handle)

                    if person is None:
                        continue 

                    datex = person.get_change_time()

I have more the same errors. I think we need filter the handles list on the export beginning and use it. Is it possible, who knows? Because this is unreal add the same conditions everywhere :melting_face:

Where export starts working from? and does it use once generated handles list or makes it multiple times?

Looks like I’ve found better solution in one place. Can I make PR for this fix? If yes, I think, I need a bit more details about the branches, etc. Or maybe anybody could make pull request instead?

For bug fixes, make the pull request against the maintenance/gramps52 branch. Then ask Serge to review it.

1 Like

If you use the “full database” during filtering, this error is displayed?

The narrative web creates tables with all the information needed to create the report.
This is to avoid 404 errors.
If you say that the handle is attached to a person in the database, how does this person relate?
In the narrativeweb.py, in the add_person, we usually add people associated.
maybe you have incorrect data ?

I am testing it right now on 5.2.2. First of all thank you a lot for the export updates. Now it works much more fast then in 5.2.1.

As for the issue. My current settings:





I also found that yesterday exception occurred on a person who didnt have birth date (an empty birth event) and didnt have death event. As I understand, such person is filtered anywhere in the scripts for security reasons. I can wrong.

@SNoiraud another thing which I can not understand is that _add_person method doesnt receive handle f6a90d766ee49515d7b8abf0c33, but later the app crashes due to f6a90d766ee49515d7b8abf0c33.
I see it by additional log:

    def _add_person(self, person_handle, bkref_class, bkref_handle):
        """
        Add person_handle to the obj_dict, and recursively all referenced
        objects

        @param: person_handle -- The handle for the person to add
        @param: bkref_class   -- The class associated to this handle (person)
        @param: bkref_handle  -- The handle associated to this person
        """
        if self.obj_dict[Person][person_handle]:
            # This person is already in the list of selected people.
            # This can be achieved with associated people.
            return

        person = self._db.get_person_from_handle(person_handle)
        if person:
            person_name = self.get_person_name(person)
            person_fname = (
                self.build_url_fname(person_handle, "ppl", False, init=True) + self.ext
            )

            if person_handle=='f6a90d766ee49515d7b8abf0c33':
                print('f6a90d766ee49515d7b8abf0c33')

I mean these two rows:

            if person_handle=='f6a90d766ee49515d7b8abf0c33':
                print('f6a90d766ee49515d7b8abf0c33')

I dont receive it in terminal.
But this handle appears later in new_person_link() method.
The current stacktrace is:

2024-10-13 14:03:27.760: ERROR: _reportdialog.py: line 801: Failed to run report.
Traceback (most recent call last):
  File "/home/yurii/projects/gramps/gramps/gui/plug/report/_reportdialog.py", line 760, in report
    my_report.write_report()
  File "/home/yurii/projects/gramps/gramps/plugins/webreport/narrativeweb.py", line 535, in write_report
    self.tab["Person"].display_pages(the_lang, the_title)
  File "/home/yurii/projects/gramps/gramps/plugins/webreport/person.py", line 178, in display_pages
    self.individualpage(self.report, the_lang, the_title, person)
  File "/home/yurii/projects/gramps/gramps/plugins/webreport/person.py", line 682, in individualpage
    individualdetail += self.display_ind_associations(assocs)
  File "/home/yurii/projects/gramps/gramps/plugins/webreport/person.py", line 1592, in display_ind_associations
    person_lnk = self.new_person_link(person_ref.ref, uplink=True)
  File "/home/yurii/projects/gramps/gramps/plugins/webreport/basepage.py", line 3056, in new_person_link
    (link, name, gid) = result
ValueError: not enough values to unpack (expected 3, got 0)

It looks like that person handles are adding into obj_dict not only in def _add_person. Maybe via some associations, references?

Additionally I added a filter in _add_person():

            if not person_name or not person_fname or not person.gramps_id:
                print(f"Invalid data for person_handle: {person_handle}")
                return

It filters about 10-15 handles. But anyway I still have exception.

One thing really helped me:

    def _build_obj_dict(self):
        """
        Construct the dictionaries of objects to be included in the reports.
        There are two dictionaries, which have the same structure: they are two
        level dictionaries,the first key is the class of object
        (e.g. gen.lib.Person).
        The second key is the handle of the object.

        For the obj_dict, the value is a tuple containing the gramps_id,
        the text name for the object, and the file name for the display.

        For the bkref_dict, the value is a tuple containing the class of object
        and the handle for the object that refers to the 'key' object.
        """
        _obj_class_list = (
            Person,
            Family,
            Event,
            Place,
            Source,
            Citation,
            Media,
            Repository,
            Note,
            Tag,
            PlaceName,
        )

        # setup a dictionary of the required structure
        self.obj_dict = defaultdict(lambda: defaultdict(set))
        self.bkref_dict = defaultdict(lambda: defaultdict(set))

        # initialise the dictionary to empty in case no objects of any
        # particular class are included in the web report
        for obj_class in _obj_class_list:
            self.obj_dict[obj_class] = defaultdict(set)

        ind_list = self._db.iter_person_handles()
        ind_list = self.filter.apply(self._db, ind_list, user=self.user)

        message = _("Constructing list of other objects...")
        pgr_title = self.pgrs_title(None)
        with self.user.progress(pgr_title, message, sum(1 for _ in ind_list)) as step:
            index = 1
            for handle in ind_list:
                self._add_person(handle, "", "")
                index += 1
                step()

            for person_handle in list(self.obj_dict[Person].keys()):
                result = self.obj_dict[Person][person_handle]
                if not isinstance(result, tuple) or len(result) != 3:
                    print(f"Removing invalid person_handle: {person_handle}")
                    del self.obj_dict[Person][person_handle]

I added this filter after all handles are added:

            for person_handle in list(self.obj_dict[Person].keys()):
                result = self.obj_dict[Person][person_handle]
                if not isinstance(result, tuple) or len(result) != 3:
                    print(f"Removing invalid person_handle: {person_handle}")
                    del self.obj_dict[Person][person_handle]

But I dont like this solution. I would like dont add broken handles instead of filtering them later