9
$\begingroup$

I'm working on a small post-save-hook, which is working pretty nicely only if the file is saved first and then the script is loaded later on. If I install my addon from the file and I save the currently opened new blender project I have this error:

AttributeError: '_RestrictData' object has no attribute 'filepath'

Which comes from the line, where I try to access the filepath data of my blender file:

path = bpy.data.filepath

When I remove my script, save the blender file and then readd my script it works again. So basically my question is:

What is the workaround of this issue? Can an already loaded module reload itself? Or is there some other way to do this properly?

Thanks in advance!

$\endgroup$

2 Answers 2

9
$\begingroup$

This is a side effect of the way you import.

from bpy import data as bpy_data imports the bpy_struct data when the py file is loaded, like a local copy (not alias). This happens during the addon registration, thus bpy_data will be and remain as:

<class 'bpy_restrict_state._RestrictData'>

In contrast, import bpy and a later use of bpy.data accesses data in the moment you actually use it. It is _RestrictData at registration time, but later on it will be

<class 'bpy.types.BlendData'>

You should change your imports from

from bpy import ( data as bpy_data,
                  context as bpy_context )
from bpy.app.handlers import ( persistent as bpy_app_handlers_persistent,
                               save_post as bpy_app_handlers_save_post )
# ...

to

import bpy
from bpy.app.handlers import persistent

# ...

@persistent    
def foobar(scene):
    bpy.data.filepath
    #bpy.context...

# ...

bpy.app.handlers.save_post.append(foobar)

from ... import ... as ... should only be used if the imported module or function would overwrite another.

$\endgroup$
2
  • $\begingroup$ That was exactly the problem. Doing the from .. import .. as .. was a micro optimisation -- as it is working quite well for python modules, reduces the number of look ups as it is adding the exact value to the global name space. Thanks! $\endgroup$
    – Peter Varo
    Apr 19, 2014 at 21:56
  • $\begingroup$ To make this work in an addon, add the foobar function to __init__.py and add the bpy.app.handlers.save_post.append(foobar) line to the def register() function $\endgroup$ Mar 14, 2021 at 7:08
3
$\begingroup$

The _RestrictData object indicates that you were trying to access stuff in bpy.data.(...) before ( blender is ready )

I don't know the technical details but I know that it happens during startup if you access bpy.data prior to register()

The first time blender reads the script is just to gather bl_info and make sure that register() is defined in the script.

After this reading of the file, blender may have other scripts to scan and so it moves on to scan the rest of the files in addons/startup...

Then, after that, if the addon is to be enabled, blender calls the script's register() ––> and from there it is usually safe to go for bpy.data.(...) or bpy.context.(...)

$\endgroup$
5
  • 1
    $\begingroup$ The line I'm referring to is inside the function which will be registered by blender itself. In my module level there is only 4 functions, two of them is the register and unregister, a dictionary, which is the bl_info and the call of the register. So I guess this shouldn't be the problem.. $\endgroup$
    – Peter Varo
    Apr 18, 2014 at 20:45
  • 2
    $\begingroup$ You're not allowed to access bpy.context and bpy.data at registration time, so not in the register() function, nor in any function that is called in inside the register() function. It typically happens 'cause one tries to give a custom property a default value - e.g. bpy.types.Scene.prop = bpy.props.StringProperty(default=bpy.context.scene.name) $\endgroup$
    – CodeManX
    Apr 18, 2014 at 22:49
  • 1
    $\begingroup$ @CoDEmanX probably I wasn't clear enough: I don't call/use any of the bpy.data nor the bpy.context in the register function. I use them in the function I register with the register function == the feature itself $\endgroup$
    – Peter Varo
    Apr 19, 2014 at 0:04
  • 1
    $\begingroup$ Please post the exact code. If you access bpy.data directly in the class scope of a class you register (and not in one of its methods), then it's the same story - it is executed immediately on registration / loading. $\endgroup$
    – CodeManX
    Apr 19, 2014 at 13:45
  • $\begingroup$ @CoDEmanX thanks for helping, here is the code. Oh, and the problem is in line 102. $\endgroup$
    – Peter Varo
    Apr 19, 2014 at 20:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .