0
$\begingroup$

There are actually 2 questions here...

I'm just starting to learn Python and I'm try to write a script to dissect a group of models and pull possible modeling problems in attributes of the Blender bpy.data.objects API that the model might might have. (unassigned bones, unweighted vertices, mesh objects that have too many vertices/bones)
My programming background (what little I have) is VBA for Office and I'm use to throwing stuff I want to grab into a temporary spreadsheet or a database Table and search those via SQL. I destroy them after I get what I need.
I'm finding the concept of lists, dictionaries, and sets difficult to comprehend (this one can have duplicates, this one can't, you can change stuff that one but not this one and I don't even want to get into list comprehension, I'm not there yet.) I have not had any luck with 2/3 dimensional arrays (which I think would solve my problem completely.), everything I've tried ends up in either a syntax or indentation error. Also, because I want to do total model summaries as well as print individual elements for each mesh, I'm finding that I have to repeat steps over and over again. (I'm not at the defining Classes and Functions stage yet.)

Situation: To mimic the environment I'm use to working in, I generating lists on the fly from strings to separate things I want to call against with a commands like:

mdlMesh = []
   for msh in object:
       if msh.type == 'MESH":
           mdlMesh.append(msh.name) # get the meshname
       if hasattrib(msh.vertex_groups):
           mdlVGrps.append(msh.vertex_groups)
           ... #'BSBound' # is returned as mdlMesh[0] and it does have Vertex Groups 
           ... # I want to dump the contexts mdlVGrps into a mesh specific list so I can
       ...     # build the Model 
       ...           
   ... # Summary Report after getting all the data before I dig into Mesh specific reporting
... 

     

if I manually type the command into the editor (I'll add this to code to the script later, I'm still experimenting with it):

>>>exec(str(mdlMesh[0]) + "_VGrps = []") # I can create a list called BSBound_VGrps from the string 
    
>>>BSBound_VGrps # I type directly into the editor to check creation and existence  
    
[]  # and find the New blank list was created, it is declared and waiting to be populated

as these are going to be created on the fly throughout the script, I'll never know if a list is actually created or not or what name I have to access (without using a string) for the information I need.

Question 1:

Is there a way to create a list of (or print) the list names created by the script?

Question 2:

Is there a way to access\call the string generated lists and populate them using a string or will I have to use the exec command to rebuild the list name again with a try statement with and argument for the elements I want to add to the lists?

Problems: The generated lists are not named consistently or may not be created at all:

example:

I'm looping through all the mesh objects in a model and creating a msh object, so the msh.name[x] in the msh.name attribute changes in each loop. I want to create a list for based each mesh object name to gather information so I'm creating them on the fly in each pass with the exe command based on the msh.name_attribute_being_pulled and adding the element of that attribute I need to the generated list name (ie "VGrps for msh.name[x].vertex_groups. = mshName_VGrps

However, the new list may not be created because there may not be data for the object attribute I'm trying to pull.

example:

the mshName object may be exist but it doesn't a .vertex_groups attribute, so the exec(str(mshName[x]) + "_VGrps = []") command is skipped over in the code and the list for that attribute is not created.

Then,

check to see if they were actually created, populate if they exist and call on them for information with a string?

example:

The list myMsh1_VGrps = [] (and a bunch of others) have been created exec command. They are empty but I have no idea if any of them exists. How can I check for existents, populate and call information from them using strings in the code?

I can't hard code direct naming like:

if myMsh1_VGrps: # because this name is different in each pass of mesh objects
    for i in myMsh1_VGrps: 
        ...
else:
    ....

or use something like

myMsh1_VGrps = ["something", "or_something_else", "BECAUSE", "I_don't_know_if_this_REALLY_Exists"] 


  

Any help would be appreciated. Thanks For reading!

$\endgroup$
11
  • 2
    $\begingroup$ Hello, I did not understand the final use of instantiating all these lists, could you elaborate on that part ? Did you explore the fact that you can have access to these lists from each object using the API ? $\endgroup$
    – Gorgious
    Mar 17, 2021 at 7:48
  • $\begingroup$ Basically, the instancing and printing of the list is just to see what lists I've managed to create on the fly while coding and to catch what might be causing errors. For example while creating lists, python errors out because a list I'm trying to create has a dot (.) in the name (like capsule.001) or the name I'm trying to use starts with a 0 and I get the invalid token error and changing to a string still throws the error. As I'm just learning Python, I need to be able to capture what I'm doing wrong so I can research the problem and change the logic of the code. $\endgroup$
    – PteJack
    Mar 17, 2021 at 15:25
  • $\begingroup$ And I don't see where I can access lists in the API. Can you provide a screen shot of where the list object or object list is? $\endgroup$
    – PteJack
    Mar 17, 2021 at 15:36
  • 1
    $\begingroup$ OK so first as you experienced it's not recommended to use exec and eval because the compiler can't really know in advance what's what and you will have trouble debugging. In most cases getattrwill do the same. Also it can execute harmful code really easily. You can access a list of objects with bpy.data.objects. See docs.blender.org/api/current/bpy.data.html You can also access a bunch of data directly from the object docs.blender.org/api/current/bpy.types.Object.html or from mesh (obj.data for a mesh object) docs.blender.org/api/current/bpy.types.Mesh.html $\endgroup$
    – Gorgious
    Mar 17, 2021 at 15:41
  • 1
    $\begingroup$ I think I understand your workflow better, and if using eval and exec suits your needs, go for it by all means :) But I'm afraid you're kind of reinventing the wheel there, mostly because you don't know (yet) where to find the relevant information. I'd advise you to start small with the API, fetch mesh data, then fetch polygons data, then fetch vertices positions, etc. All these containers are available without using voodoo magic and you don't run the risk of having duplicated data be outdated by the time you evaluate it somewhere else $\endgroup$
    – Gorgious
    Mar 17, 2021 at 19:50

2 Answers 2

1
$\begingroup$

Working my way through this and learning what little I have about lists(arrays), tuples and dictionaries, I think the best way to go about this is to use dictionaries. Using Keys I can name them whatever I like, I can stack them with values I need and I can get away from using dangerous commands like exec and eval which all of a sudden aren't performing the way they were when I posted my last answer (I probably fluked something when I was working with them and got the results I was looking for.)

Now I just have to get list comprehension down in order to build my dictionaries properly and minimize the for - while and if statements I'm writing in the code.

Thanks to everyone who have read and especially those who responded.

$\endgroup$
0
$\begingroup$

I think I have the answer...

After the exec command runs, do an evaluate and stash a true\false return somewhere.

exec(str(msh.name[0]) + "_VGrps = []")
result = isinstance(eval(str(msh.name[0]) + "_VGrps"),list)
if Result == True:
   newlist.append(str(mdlMesh[0]) + "_VGRps")
else:
   listfail.append(str(mdlMesh[0]) + "_VGRps")

This is the result of a test I just ran:

>>> exec(str(mdlMesh[0]) + "_VGRps = []")
>>> result = isinstance(eval(str(mdlMesh[0]) + "_VGRps"),list)
>>> print(result)
True

another test

>>> str(mdlMesh[0]) + "_VGRps = []" 
'BSBound_VGRps = []'

>>> eval(str(mdlMesh[0]) + "_VGRps") 
[]

And the check may not even be necessary... you can append directly to the str(mdlMesh[0])+ "_vGRps" list is it exists

 eval(str(mdlMesh[0]+"_VGRps")).append("THIS IS A TEST")
>>> BSBound_VGRps
['THIS IS A TEST']

And my answer to the Topic question is:

>>> for a in vars():
...     if isinstance(eval(a),list):
...         print(a)
...         
mdlNoParMod
mdlVerts
mdlParent
mdlArmatures
mshName
mdlBones
boneLayers
armDataName
vg
mdlMesh
mdlVGrps
BSBound_VGRps
$\endgroup$

You must log in to answer this question.

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