1
$\begingroup$

I think I know how to make a report that contains information from the info window. I think the report is saved in a textblock called ‘recent reports’.

My question. How do I read the textblock, or how do I ‘print’ the textblock, or how do I save a file of ‘recent reports’?

I have read: How do I get the Info window's log text with Python?

How to use the textblock operator in Python

https://blenderartists.org/t/copy-from-info-panel/700032/2

$\endgroup$
2
  • $\begingroup$ Do you want a script that simply saves the contents of the INFO window to a file? $\endgroup$
    – rob
    Commented Aug 7, 2019 at 8:01
  • $\begingroup$ @rob Yes I want a script that simply saves the contents of the INFO window to a file. Even better, I would like a file that contained all the current settings to a file. I want to try different settings in Blender and have a readable record of the settings that were used. $\endgroup$ Commented Aug 7, 2019 at 9:38

2 Answers 2

3
$\begingroup$

Recent Reports

Modifying code from https://blender.stackexchange.com/a/62620/15543

The code in answer prints the textblock.

This one removes all other recent reports from blend file, creates a new one via operator, and writes it to filepath

import bpy


#remove other Recent Reports
reports = [bpy.data.texts.remove(t, do_unlink=True) 
           for t in bpy.data.texts
           if t.name.startswith("Recent Reports")]
# make a report
bpy.ops.ui.reports_to_textblock()
# save the report to file

filepath = "recent_reports.txt"
with open(filepath, "a") as f:
    f.write(bpy.data.texts["Recent Reports"].as_string()) 

Alternatively, if you don't want to clean up others, the new text added by operator can be found using sets.

import bpy

texts = set(bpy.data.texts)
bpy.ops.ui.reports_to_textblock()
new_text = (set(bpy.data.texts) - texts).pop()
filepath = "recent_reports.txt"
with open(filepath, "a") as f:
    f.write(new_text.as_string())

both write to a file "recent_reports.txt" in the same folder blender was opened

$\endgroup$
12
  • $\begingroup$ That works for me up until # save the report to file. The f-string needs Python 3.6 Blender 2.79 comes with Python 3.5 so I need the code without the f. Please. $\endgroup$ Commented Aug 7, 2019 at 9:30
  • $\begingroup$ do you get an error or can not find the resulting file? $\endgroup$
    – rob
    Commented Aug 7, 2019 at 9:32
  • 1
    $\begingroup$ @PaulStGeorge I get a file named "recent_reports.txt" in the folder I started blender. I have write permission to that folder. Edit filepath to a folder that you can write to. What f-string? Surely with open(...) as f: predates 3.5... anyway it is just simple text file io. Change to suit your python version if need-be. $\endgroup$
    – batFINGER
    Commented Aug 7, 2019 at 9:52
  • $\begingroup$ ... oh and don't edit the filepath using f-string formatting. $\endgroup$
    – batFINGER
    Commented Aug 7, 2019 at 10:04
  • 1
    $\begingroup$ Now I have done this: 'Edit filepath to a folder that you can write to.', it all works perfectly. $\endgroup$ Commented Aug 7, 2019 at 14:58
2
$\begingroup$

I leave this here since in the last version the above solution is not anymore valid. Code snippet:

import bpy

def GetMacro(name):
    if name.startswith("bpy.ops"):
        try:
            return eval(name.split("(")[0] + ".get_rna_type().name")
        except:
            return name
    elif name.startswith('bpy.data.window_managers["WinMan"].(null)'):
        return True
    elif name.startswith('bpy.context'):
        split = name.split('=')
        if len(split) > 1:
            return split[0].split('.')[-1] + " = " + split[1]
        else:
            return ".".join(split[0].split('.')[-2:])
    else:
        return None
    
def getlastoperation(data, i=-1):
    if len(data) <= 1:
        return ("", i)
#    if data[i].body.startswith("bpy."):
#        return (data[i].body, i)
    else:
#        return getlastoperation(data, i-1)
        return (data[i-1].body, i-1)
    
def CheckAddCommand(data, line = 0):
    name, index = getlastoperation(data)
    macro = GetMacro(name)
    if macro is True:
        return CheckAddCommand(data[ :index], line + 1)
    else:
        return (name, macro, len(data) + line - 1)

def Get_Recent(Return_Bool):
    #remove other Recent Reports
    reports = \
    [
    bpy.data.texts.remove(t, do_unlink=True)
    for t in bpy.data.texts
        if t.name.startswith("Recent Reports")
    ]
    # make a report
    win = bpy.context.window_manager.windows[0]
    area = win.screen.areas[0]
    area_type = area.type
    area.type = "INFO"
    override = bpy.context.copy()
    override['window'] = win
    override['screen'] = win.screen
    override['area'] = win.screen.areas[0]
    bpy.ops.info.select_all(override, action='SELECT')
    bpy.ops.info.report_copy(override)
    area.type = area_type
    clipboard = bpy.context.window_manager.clipboard
    bpy.data.texts.new("Recent Reports")
    bpy.data.texts['Recent Reports'].write(clipboard)
    # print the report
    if Return_Bool == "Reports_All":
        return bpy.data.texts["Recent Reports"].lines
    elif Return_Bool == "Reports_Length":
        return len(bpy.data.texts["Recent Reports"].lines)
    
Recent = Get_Recent('Reports_All')
name, macro, line = CheckAddCommand(Recent)

print("Message: {}".format(name))
print("Macro: {}".format(macro))
print("Line: {}".format(line))

bpy.data.texts.remove(bpy.data.texts['Recent Reports'])

It is mainly a restructure of some functions from the linked addon which most likely seems to do what @batFINGER suggests above to me. If there is a simpler solution/approach please feel free to edit.

$\endgroup$
5
  • $\begingroup$ Hmmm I get this error: IndexError: bpy_prop_collection[-2]: out of range. $\endgroup$ Commented Apr 13, 2021 at 19:05
  • $\begingroup$ what is the length of data inside the getlastoperation() function? Most likely, the error comes from there. $\endgroup$
    – ttsesm
    Commented Apr 14, 2021 at 20:18
  • $\begingroup$ As I was guessing this is because the log window is empty. Replace if len(data) < 1: with if len(data) <= 1: and it should work. I also updated the code above. Thanks for the notice ;-). $\endgroup$
    – ttsesm
    Commented Apr 14, 2021 at 21:26
  • 1
    $\begingroup$ That now works perfectly! You were right about the log being empty at first. Now, all the information is copied to the clipboard and I can then paste this into a text file. It would be useful to extend the code so a text file is created that includes the information. That would be even better. Is it possible? $\endgroup$ Commented Apr 15, 2021 at 12:16
  • 1
    $\begingroup$ It is the same approach as in @batFINGERS solution, just add: filepath = "recent_reports.txt" with open(filepath, "a") as f: f.write(name.as_string()) as you can see we just replace the variable to be saved which in our case is the name. $\endgroup$
    – ttsesm
    Commented Apr 16, 2021 at 10:27

You must log in to answer this question.

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