Page MenuHome

Inconsistent behavior of bpy.utils.user_resource( ) function
Closed, ResolvedPublicTO DO

Description

Operating system: Windows-10-10.0.17134 64 Bits
Graphics card: Quadro P4000/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 412.16

Blender Version
Broken: version: 2.80 (sub 50), branch: master, commit date: 2019-03-19 06:43, hash: rB4db7842a72cc
Worked: unknown, 2.79 latest shows same behavior

Short description of error
As a few times before, this is in conjunction with having a custom user_scripts path via environment variables BLENDER_USER_CONFIG and BLENDER_USER_SCRIPTS. When using the bpy.utils.user_resource( ) function for an own add-on, I came across something strange: Passing only the resource type (for instance 'SCRIPTS') to it yields the correct location of my scripts. Passing the optional sub-directory suddenly defaults back to the ones in C:\Users\ME\AppData\etcetc. See output from Blender Python console:

>>> bpy.utils.user_resource('SCRIPTS', 'test')
'C:\\Users\\ME\\AppData\\Roaming\\Blender Foundation\\Blender\\2.80\\scripts\\test'

>>> bpy.utils.user_resource('SCRIPTS')
'D:\\_PREFS_REFACTOR_\\_28_\\UserConfigs\\..\\scripts\\'

>>> bpy.utils.user_resource('CONFIG', 'test')
'C:\\Users\\ME\\AppData\\Roaming\\Blender Foundation\\Blender\\2.80\\config\\test'

>>> bpy.utils.user_resource('CONFIG')
'D:\\_PREFS_REFACTOR_\\_28_\\UserConfigs\\ME\\'

This makes the creation of shared custom presets for my Add-on operator impossible for me, as the preset never lands on the network drive.

Exact steps for others to reproduce the error

  1. Set Blender User Scripts path and User Config path to a custom location first (on Windows, create environment variables BLENDER_USER_CONFIG and BLENDER_USER_SCRIPTS and assign path locations to it).
  2. Open Blender, go to Python console, test the output of the commands bpy.utils.user_resource('SCRIPTS', 'test') and bpy.utils.user_resource('SCRIPTS').

Event Timeline

Philipp Oeser (lichtwerk) lowered the priority of this task from 90 to 50.Mar 19 2019, 10:16 AM

Confirmed, checking...

Seems to be working if the folder actually exists.
Not sure about the logic in bpy_user_resource / BKE_appdir_folder_id_user_notest [responsible for falling back to get_path_user instead of get_path_environment if the combined path doesnt exist...]

There is also following comment there:

same logic as BKE_appdir_folder_id_create(), but best leave it up to the script author to create

so it seems to be designed to leave it up to the user to create the directory first...
imo this could/should be changed -- making it consistent like the report suggests...

will look into implementing this (unless @Campbell Barton (campbellbarton) has objections?)

Looking into this, from what I can tell the report is that the environment variable should take priority over the users scripts directory when neither exist.

While a reasonable suggestion this isn't a bug.

Note that creation is handled by bpy.utils.user_resource(resource_type, path="", create=False).

Allowing create=False is useful since you can know if the directory doesn't exist and not attempt to read it's content.


Any users of this API that want to use the first scripts path found (environment var) can use os.path.join(bpy.utils.user_resource('SCRIPTS'), 'test').

Setting as TODO.

@Campbell Barton (campbellbarton) : thing is that even if the directory specified in BLENDER_USER_CONFIG environment variable exists, it will fallback to get_path_user if the specified subfolder doesnt exist.
(this is because BKE_appdir_folder_id_user_notest does indeed test if the directory exists indirectly, so calling it _notest is pretty much nonsense...)

@Campbell Barton (campbellbarton) bpy.utils.user_resource(resource_type, path="", create=False) is indeed useful. The bug report however tackles a case which is buried within the AddPresetBase class. There, bpy.utils.user_resource(resource_type, path="somesubpath", create=**True**) is called. The subpath IS then created as it should be, but not within the path coming from get_path_environment. The location it ends up in is unexpected and undesired from a user's side.