burghoff / Scientific-Inkscape

Scientific Inkscape: Inkscape extensions for figure resizing and editing
528 stars 20 forks source link

AttributeError: 'NoneType' object has no attribute 'iddict' #24

Closed turing closed 7 months ago

turing commented 7 months ago

Describe the bug

In an extension, this code runs:

84:        svg_path = ClipPath._rect_circle_cut(
85:            radius,
86:            config.SVG.get_page_bbox().width,
87:            config.SVG.get_page_bbox().height,
88:            origin
89:        ) # just returns svg path data
90:        
91:        path = inkex.elements.PathElement()
92:        path.set('d', svg_path)
93:        path_id = config.SVG.get_unique_id(f"{eid}_path_")
94:        path.set_id(path_id)
95:        
96:        path_data = svg_path

Path id returned is a string, something like ext_outside_circle_clip_path_0

Results in:

  File ".../clippath.py", line 94, in outside_circle
    path.set_id(path_id)
  File ".../lib/text/cache.py", line 636, in set_id_mod
    self.croot.iddict[new_id] = self
AttributeError: 'NoneType' object has no attribute 'iddict'

This is happening only after a version upgrade.

To Reproduce Run my code :)

SVG attachments Happy to provide privately.

Error messages See above

Inkscape version: Inkscape 1.3 (0e150ed, 2023-07-21)

turing commented 7 months ago

inkex.BaseElement.set_id = set_id_mod # type:ignore

Commenting out line 644 fixes my problem (at least temporarily!)

burghoff commented 7 months ago

It's failing because the caching added by the text submodule assumes that IDs are set after they are added to documents. Your workaround will probably break a lot of the caching.

For a more robust temporary solution, add the element to the SVG (i.e., insert or append it somewhere) before setting the ID.

turing commented 7 months ago
AttributeError: 'NoneType' object has no attribute 'iddict'

is the result of this:

   def outside_circle(origin, radius, eid, label):

        svg_path = ClipPath._rect_circle_cut(
            radius,
            config.SVG.get_page_bbox().width,
            config.SVG.get_page_bbox().height,
            origin
        )

        path = inkex.elements.PathElement()
        path.set('d', svg_path)
        path_id = config.SVG.get_unique_id(f"{eid}_path_")
        path_data = svg_path

        clip = inkex.elements.ClipPath()
        clip_id = config.SVG.get_unique_id(f"{eid}_")
        clip.append(path)

        # THIS IS CRITICAL. NOTE THE APPENDING TO DEFS
        config.SVG.defs.append(clip)

        path.set_id(path_id)
        clip.set_id(clip_id)

        path_element = elements.add(path, label) #elements is a structure in my extension, it's being added to the DOM above.
        clip_element = elements.add(clip, label)

The IDs are now set after the elements are added to the SVG, but I get the same result.

burghoff commented 7 months ago

The dev version should work now. Let me know if it's fine and I'll close the issue.

turing commented 7 months ago

Checked out dev, pulled the lib, getting:

  File "/items.py", line 1036, in create_concentric_clip_group
    clip_subgroup.append(item.inkex_item)
  File "/lib/text/cache.py", line 1384, in append_func
    oldroot = el.croot
AttributeError: 'NoneType' object has no attribute 'croot'

My source:

        svg_path = ClipPath._rect_circle_cut(
            radius,
            config.SVG.get_page_bbox().width,
            config.SVG.get_page_bbox().height,
            origin
        )

        path = inkex.elements.PathElement()
        path.set('d', svg_path)
        path_id = config.SVG.get_unique_id(f"{eid}_path_")
        path_data = svg_path

        clip = inkex.elements.ClipPath()
        clip_id = config.SVG.get_unique_id(f"{eid}_")
        clip.append(path)

        # THIS IS CRITICAL. NOTE THE APPENDING TO DEFS
        config.SVG.defs.append(clip)

        path.set_id(path_id)
        clip.set_id(clip_id)
burghoff commented 7 months ago

Not replicated—similar code is fine for me (I took out _rect_circle_cut since I don't have that).

It looks like a problem in items.py, as it's trying to append a None to the document somewhere. I don't know what that is, though.

burghoff commented 7 months ago

Note that appending None to a document fails even without the text submodule:

File "sandbox.py", line 115, in effect
    self.svg.append(None)
TypeError: Argument 'element' has incorrect type (expected lxml.etree._Element, got NoneType)
turing commented 7 months ago

Nevermind! The second error was my fault! :) Your changes solve the issue.