Creating and debugging Python scripts in Blender with SPE and Winpdb
Witold Jaworski October 2007
Edited/Input by Jeffrey Blank January 2008
To begin with, in this tutorial I will not dig too deeply into many of SPE's feature that are not connected directly to Blender. This would take too long.
All information presented here is based on my own experience. For sure, I am not the most skillful user of either Blender or SPE. If you find that I have made a mistake in any place, feel free to correct it.
The following software is required to run SPE within Blender and needs to be installed in the order shown.
The version of Python used to create this tutorial was 2.5.1. The version of Python that should be installed is dependent on the version and build of Blender you are running. The standard build of Blender 2.45 for Windows looks for Python 2.5. Windows systems do not have Python pre-installed. For details of a typical Windows install, see Appendix A.1.
Mac Os X and most Linux distributions ship with a standard Python installation by default. If this version is different from the one required by Blender, you will need to install the version that Blender requires. (For example to install Python 2.5 on Ubuntu: type "sudo apt-get install python2.5" at a terminal.
The version of wxPython used to create this tutorial was 2.8.6 (for Python 2.5). Installation packages of wxPython for all operating systems may be downloaded from wxPython.org. Appendix A.2 shows a typical wxPython installation for Windows.
The version of SPE used to create this tutorial was 0.8.4b (this version must have a build date after 23rd October 2007) The installation files should be available from pythonide.stani.be. The required version is only available by svn access at this time. SPE needs to be installed at C:\Program Files\Python\Lib\site-packages\_spe\ for Windows and /usr/lib/python2.5/site-packages for Linux. I will refer to this directory as site-packages for the rest of the tutorial.
I have not mentioned Blender, version 2.42 or higher, because you probably already have it installed!
First Steps in SPE
After you have finished installing the software, you can run SPE from the Blender for the first time. Open the site-packages\_spe\spe.blend in Blender. The Blender screen should look like figure 2.1.
You will see Blender's Text Editor window in the bottom panel. The editor will contain the SPE startup script. To run SPE, press AltP or select the Run Python Script command from File menu. This will open the SPE editor window as shown in figure 2.2
SPE is really rich Python editor written by Stani (pythonide.stani.be). You can search for fragments of its description dispersed on the Web or buy its manual for which the small cost is a donation to further development of this program. (Look at the smiling face on Donate tab - isn't it encouraging to do this?).
To make the SPE shell recognize the Blender module and it's children, I have typed "import Blender" as the first statement. You can now see that SPE uses syntax coloring in the shell window. The SPE shell now recognizes Blender functions and procedures and is attempting to help finish the commands that I am typing. In addition to commands, the SPE Shell also attempts to help me by suggesting object attributes (figure 2.4) and function descriptions (figure 2.5).
This interactive shell lets you play with live Blender objects. It gives you a quick way to try out ideas and concepts you may have while writing a script.
There is also a special Blender tab, which lets you explore the Blender API.(figure 2.6). It wouldn't hurt to take a quick look through this tab. Who knows, maybe you'll discover commands you didn't know even existed!
There is also a Blender menu available when running SPE from within Blender (figure 2.7). (The menu is not visible when SPE is being run as a standalone application.) The first section of the Blender menu contains two commands that will be described in detail later on in this tutorial:
- Load into Blender: loads current script into Blender as a Text datablock that can be changed in Text Editor window;
- Reference in Blender: appends current script to Blender Scripts menu in Scripts Window.
The third and fourth section of Blender menu contain links to related documentation sites.
The fifth section contains only one command: Add SPE and Windpdb to Blender menu. It adds two shortcuts (one for SPE, the second for Winpdb, the debugger) to Scripts → System menu in the Blender Scripts Window. (It is a kind of installation command which you usually have to run only once).
Now, if we are going to use two different editors for the same Python script, we should synchronize their tab settings. The Python interpreter is very sensitive to this! When you type a ⇆ Tab in the Blender Text Editor, it puts a tab character into script text. It is not converted automatically into spaces. You have to issue a special command from Format menu to make that happen. It would be an annoying task to convert tabs to spaces over and over again. So, let's use tabs for spacing in both editors. It is good idea to set them at the beginning. To do this, select the Preferences command from Edit menu. (figure 2.8)
Once the Preferences dialog window is open, go to the Editor tab (figure 2.9) and click on the Use tabs checkbox and make sure that the Tab width is set to 4 (or whatever you have tabs set to in the Blender Text Window). You can also check the Refresh Time Interval setting for redrawing the Blender window under the General tab as shown if figure 2.10.
That's all we will do this first time in SPE. Now, when you close SPE, you will be back in Blender, and it will start to react on your commands again.
Some Blender Features Related to Python
Before we start to write a Python script in SPE, I would like to present some of the features in Blender that we will use in this tutorial. Of course, there are also other utilities related to Python - it is not reasonable to describe all of them here.
Adding SPE and Winpdb Commands to the Blender Scripts Menu
What did this command do? It has copied from site-packages\_spe\ the following files:
- winpdb_blender.py (implements the Blender menu Scripts → System command Attach WinPdb debugger)
- spe_blender.py (implements the Blender menu Scripts → System command Stani's Python Editor)
and placed them in either the Blender\.blender\scripts\ directory or the user script directory. I think that the user script directory is a better place for your Python files. This way, they won't be affected by Blender upgrades. You can set the User script directory in Blender's User Preferences Window in the File Paths section. See figure 3.2.
If you change this setting after you ran the Add SPE and Winpdb command, you may want to rerun the command to copy the two scripts to your new script directory. This will also let SPE know where you are storing your scripts.
After running this command, you will find two new commands in the System submenu, Attach Winpdb debugger and Stani Python Editor. Later in this tutorial you will learn how to add your own commands to the Blender script menu. It is very easy, especially in SPE.
Browsing Online Documentation of the Script Commands
To access this additional documentation, switch to the Blender User Preferences window, and from the Help menu select Scripts Help Browser command (figure 3.4). You should see a dialog box similar to figure 3.5 in an open Scripts Window. From this menu, you can select a program by pressing the Blender menu buttons. Each of these buttons matches a submenu from Scripts menu. (figure 3.6)
When you select an item, a detailed description of the selected script will be shown in the window as in figure 3.7. If you press the source button, the content of the script will be loaded as a Blender Text item into the current Blender file as shown in figure 3.8. This item bears the name of the script file. You can look at it by opening Text Editor window, presented in the next section.
Text Editor Window
Now that we have a script loaded, let's turn on the Python specific features, line numbers and color syntax. Press the corresponding toggle buttons, as shown in figure 3.11.
When you want to run this script press AltP or select the File → Run Python Script command. When you are going to debug a script inside Blender - running it from this window is the only possible choice. Otherwise the Winpdb debugger, due to an internal error in Blender, will not be able to show the source lines.
Making a Script (or How to Make SPE and Blender Play Well Together)
In this section of the tutorial we will create a script that implements an operation that is missing in Blender. In Blender, it is possible to align a view to a selected object, but the view is always aligned to XY plane of selected object. (If you want to try select the cube and go to object mode, View → Align View → Align View to Selected). When modeling moderately complicated mechanical assemblies, like the landing gear of an airplane, I often want to align the view to any plane of an object. (i.e. ZX, YZ, ...) It is currently not possible to perform this operation. So... let's create a script for aligning the view that:
- will be registered in Blender's Object → Scripts menu as Align View to Selected command. (View menu would be more appropriate, but it has no Scripts item, so you cannot add your script there);
- will display a popup menu, where the user will be able to select the object plane (ZX, YZ, ...);
Let's start. Open Blender. For developing this script, we will use the default model, a single cube.
Switch the upper User Preferences panel into Scripts Window and select the Scripts → System → Stani's Python Editor command (remember we added it earlier in this tutorial?)
SPE may take a few seconds to open the first time it is called in a Blender session but all subsequent calls will load much quicker. (usually less than a second!) After the SPE window appears, we can type the beginning of the script as shown in figure 4.1.⇧ ShiftCtrlE.
We start the writing script code with a crude version of the user interface, not touching the main task at all. Believe me, this way will allow you to create the script quicker, rather than coding the "internals" first and then creating the user interface at the end. (This is the way most beginning script writers do it.) After all you are the first user of your script, so make it easy on yourself! In fact, the user interface provides the means for the user to enter data and interact with your script. If the data that is input is wrong, even the best code in the script "internals" won't be able to help.
Now, let's save this script with the name "align_view.py". (SPE automatically checks the script for syntax errors). Then it is time to run it. Because there may be some errors in the code, we will load this script into Blender Text editor, and run it from there. To load it into Blender, select Blender → Load into Blender command (Figure 4.2) or press CtrlB. The result of this operation is shown on the SPE status bar.
Now we will close SPE and select the 'align_view.py' datablock in Blender. Switch the lower Blender panel into a Text Editor window. Remember, you always have to select the script data block from dropdown menu of the list items as shown in figure 4.4. (Blender never automatically shows the newly created/reloaded text item).
So here we have the script in a Blender Text editor window. Turn the line numbers and color syntax toggles on by pressing the buttons in the header bar. (figure 4.5)
Next, use File → Run or AltP to execute the Python Script, and as we see in figure 4.6...
... we have an error! When you click the message, the error line will be highlighted in a pink color as shown in figure 4.7 (for the default Blender theme).
OK, let's do what Blender told us to do, look at the Blender console to see what is wrong with this highlighted line. (figure 4.8)
It seems that I typed the function name too fast and didn't use the SPE code completion feature. It should be GetSelected(), not getSelected(). Let's correct this error in the Blender Text Editor and save it with File → Save, or AltS. The first time you save the file, Blender asks you to confirm that you want to save over the existing file, as shown in figure 4.9. Because we have saved this file, SPE will open the updated version the next time we run it.
OK, let's run our script again to see what happens (AltP)... No error message from Blender? Nice, so probably everything is working properly when we have one selected object in Blender scene. Now let's try the case in which nothing is selected. Go into the 3D View Window and press the A key (or the Select/Deselect All command from Object menu) to deselect the cube. All the objects in current scene should be deselected at this point. Lets run the script again (figure 4.10)...
Great! The script works as we want.
So now, let's go back to SPE (Scripts → System → Stani's Python Editor). As you can see in figure 4.11, we have added to the script to create a pop-up menu for data entry.
To make the code cleaner, the string that defines the popup menu has been set to a global MENU variable. My intention is for it to be a constant, so I marked this area as a "constants" section. The text after the "|" in the MENU string defines a single menu item. The expression "%x<digits>" is evaluated to an integer and returned by function PupMenu(). If the option selected from menu exists (that is, the user has not cancelled the operation), we will obtain the required user input. At this point the "core" function (ChangeViewTo) will be called and it will change the current view. On this phase of the script development, ChangeViewTo() does nothing, it just prints a diagnostics message to the console to let us know that it was called.
Let's load the revised script into Blender and see how it works. Save the script (CtrlS), send it to Blender (CtrlB) where it will replace the previous version of the align_view.py datablock), and close SPE (AltF4). Notice, that the align_view.py text was not initially selected in Blender Text Editor. As noted earlier, this is normal when updating the script from SPE. Now we load the script into the Text Editor by selecting align_view.py from the drop-down list. You should see something similar to figure 4.12.
After the script is loaded, select the cube in the 3D View window (since we deselected it in the previous step) and switch back to the Text editor and run the code with AltP. You should see the pop-up menu as shown in figure 4.13.
We see the menu in figure 4.9. Let's run it few times, looking at the diagnostics messages on the console (printed by ChangeViewTo(), figure 4.14). OK, ChangeViewTo() is called each time.
Now another test. Run the script again but do not select ANY item from "Object plane:" menu, press Esc instead. This will simulate a user who decided that they wanted to cancel this operation. In case of user cancellation the ChangeViewTo() should not be called, there is a conditional clause in line 23 for this case (see the script source in SPE in figure 4.11).
After cancelling out of the command, look at the console (figure 4.15). There should not be any new message from ChangeViewTo(), but.... THERE IS!?
Next, we have to debug the script to determine why ChangeViewTo() was called!
Script Debugging - Using Winpdb With Blender
Attaching Winpdb to Blender
From the Scripts Window select the Scripts → System → Attach Winpdb dDebugger command as in figure 5.1.(remember that we added it earlier from within SPE.)
After a while (a few seconds), the Winpdb window will open and you will see a screen similar to figure 5.2. The warning shown in the picture will always appear when you attach Winpdb to Blender. Click Ok to continue. You will then get a second warning as shown in figure 5.3. This is also normal. Click Ok to continue. I have tried to press Cancel to ignore this warning in the future as directed by the dialog box but the warning has always appeared.
Winpdb, An Introduction
Winpdb was written by Nir Aides as a platform independent GPL Python debugger. It supports multiple threads, namespace modification, embedded debugging, encrypted communication and is up to 20 times faster than pdb. (Taken directly from the Winpdb website.) The documentation is available at Winpdb website, easily accessible through the Help → Online docs command. There are also links to external tutorials. As with our discussions of SPE, I will only concentrate on using Winpdb with Blender in this tutorial. (If you want to support the Winpdb development you can go here to donate.
The Winpdb screen is divided into five panels as shown in figure 5.4. There are three panels (Namespace, Threads and Stack) on the left and two panels (Source and Console) on the right. For debugging this single-threaded Python script, I used the following panels:
- Source: shows the source, associated breakpoints, and executed line. Its functionality is similar to other debuggers;
- Console: shows some messages from Winpdb (in the picture you can see the sequence of messages from attaching Winpdb to Blender). It also shows results of commands typed in the Command line located below under the console window.
- Namespace panel: allows to check values of all local and global variables;
- Threads Panel: Since this script uses only a single thread I did not use this panel.
- Stack panel: shows current stack of Python function calls;
You can find a detailed description of Winpdb screen in a tutorial written by Chris Lasher.
Getting back to our script, we have now attached Winpdb to Blender but the source for the script we just ran did not appear in the source window! This is normal. It is specific to Blender (and may be an old bug, I don't know) that you are able to see only the source shown in Text Editor window. Since the script for this command was called from the Script menu, Winpdb can only see its stack and the line number of currently executed line. Anyway, we do not need to see it since we want to debug our script, not the menu command! So, in the Winpdb window click Go push button (or Control → Go, or press F5), to finish the menu command and unfreeze Blender. The state of Winpdb has been changed from "WAITING AT BREAK POINT" to "RUNNING" (The current status is shown at the bottom of Winpdb window, compare it with the state from figure 5.2). The cursor sometimes can be shown as a hourglass but Winpdb is still responsive. It will break into your code when you issue the Control → Break (F4) command while you are running a Python script in Blender.
Debugging Our Script
In Winpdb window issue the Break command if you haven't already done so. (You can also issue this command by pressing F4 or Control → Break from the menu). It will freeze Winpdb until you run a script in Blender.
Switch to Blender, and run the script from Text Editor window (press AltP or select File → Run Python Script command)
And here we are! Winpdb has caught the first line of our script as shown in figure 5.7. Let's issue the Next command (F6). After issuing the Next command once, the highlighted line has not been changed but its status changed from "C" to "L" as shown in figure 5.8. After pressing another F6, Winpdb starts to move through the script, line by line.
When it reaches line 27 (the call to main()), use Control → Step Into (F7), instead of F6 (Next). You will enter the main() function. Place the cursor on line 23 and select Breakpoints Toggle → Breakpoint (or press F9) to tell Winpdb to stop there (it's better to skip over a function that calls the user interface)(figure 5.9) Then press F5 (or Control → Go) to let Blender to show the popup menu.
You will have to switch to Blender window and it may happen that you will not have a chance to select anything from the popup menu of your script. Blender's popup menus are very volatile. It seems that switching to the Blender window is enough for them to assume that the user has canceled the operation. Lucky for us, we want to test exactly this situation, cancellation of the menu. So, with your manual selection or without, you will reach the Winpdb breakpoint at line 23 as shown in figure 5.10.
When you look at the values of the variables in the Locals window pane in figure 5.11, you will see the reason that the ChangeViewTo() function was called again. When I created the conditional if statement at line 23, I assumed that Blender.Draw.PupMenu() returns None when user cancels the command. (This is the normal response from most other Python functions). Here I was wrong, and had not read the Blender API reference carefully enough. When nothing is selected or the action is cancelled, PupMenu() returns a value of -1! We have to change the test expression in the statement at line 23.
To test if the rest of the algorithm is OK, let's change value of the option variable in Winpdb. We will use the command line to do this. First, I will show you how to evaluate any Python expression in Winpdb. Since this debugger has no special Watch window, you have to use the "evaluate" command quite often. To begin with, type any expression in the Command line as shown in figure 5.12. When you press ↵ Enter, it will be evaluated in the Console as shown in figure 5.13. Rather than typing "eval" each time, you can use the shortcut: "v" as we do in figure 5.14).
To change value of a variable, use the "exec" command as in figure 5.15. When you press ↵ Enter, you will see the result in the Namespace → Locals tab. (figure 5.16) The shortcut for "exec" command is "x".
I didn't change the value of the option local variable just to show you how to do it, I also had another goal, to show you how Winpdb marks the return from a function. Now you press F7 (Step Into) just to check if the script will enter the ChangeViewTo() function at line 23. Notice that the current line has been moved to the last line of the procedure, and its status is not "L", but "R" like in figure 5.17
At first glance it may seem strange that the script did not execute line 25 after line 23, but the answer for this mystery is the status of the debugee, on the left side, "R" means "Return". The script is just leaving the whole function, using the implicit return statement. So everything is in its proper place.
Press F5 (Go) to let Blender finish the script.
The source remains on the screen, even though Winpdb is no longer debugging our script. The state of Winpdb is "RUNNING". In this way, we have come back to the initial state of the environment.
You can now modify the code as needed. If the change is small you can quickly do it in Blender's Text Editor and save the updated version. If you have to redesign something, open SPE and make the changes to the script because it will be much more easier to do it there. Winpdb will patiently wait in the background until you need it again When you do need to run winpdb again, repeat the steps starting at the beginning of this section. (set Winpdb into Break mode by pressing F4, ...)
Detaching Winpdb from Blender
Usually, you will not need to do this manually. You should always close Blender first and Winpdb second. Otherwise, if you close Winpdb before Blender, Blender will crash at shutdown. If, for any reason, you want to close Winpdb before Blender, you have to issue a special Detach command. To detach Winpdb manually from Blender, break into any running script first and then issue the Detach command. (Winpdb needs to have a Python engine in active state to detach, that is the trick). So:
- set Winpdb into break mode (as described in previous paragraph);
- run any Python script (I often used Help → Tutorials command from User Preferences window for this purpose)
When Winpdb stops at the beginning of the script, issue the File → Detach command in Winpdb as shown in figure 5.18. Successful completion of this operation is shown on Winpdb console. (figure 5.19) After this, you can safely close Winpdb and the subsequent Blender shutdown should happen without any problem.
Adding the Script to Blender's Menu
Using SPE and Winpdb I have finished this script. The goal of this tutorial is to show how SPE and Winpdb can be used as a kind of IDE for Python in Blender, so I will not dig into details of changing the 3D view matrices. You can find the finished script at the end in Appendix D. Figure 6.1 also shows the rest of the new code to make this script work.CtrlAltB)
If our script was saved in a directory other than the Blender script directories for Python commands:
- user script directory
it will be saved to one of these locations (these directories were already discussed here). First, SPE will try to save it to the user scripts directory, if it exists. If not, the script will be saved to Blender\.blender\scripts\. A message will appear in the status bar. The status bar informs us that the file was saved in new directory and Blender's signature was added. What is Blender's signature? It is a special beginning of the file, required for Blender menu commands. Figure 6.3 shows a typical Blender signature. You can find a detailed description of the Blender signature format in the Blender Python API Reference in the section titled "Registering scripts".
While creating this signature, SPE tries to automatically determine some of the details, like your user name and current version of Blender. All you have to do is to change this content as needed to match your script and save the changes. Let's start with lines 1 through 8. They are required by Blender, and you should modify the text in apostrophes only:
- Name: name to be shown in Blender's menus;
- Group: name of the submenu in the Scripts menu in Scripts Window. You are only allowed to use the existing names. This script will be placed there as <Name>;
- Blender: the minimal Blender version, - numerical and without a dot (e.g. 245 for version 2.45);
- Tooltip: a one sentence description of the command;
Figure 6.4 shows what I used for the align view script we created in the previous sections.
Warning: I have encountered a problem with the optional #Submenu line that is described in the Blender Python API Reference. It seems that Blender does not behave as described and just ignores such lines.
I have also modified the documentation info (from line 11 to the end of the signature). It is used by the Scripts Help browser. (figure 6.4) OK, Now that we have updated all of the signature elements, let's save the file (CtrlS). Then close SPE (AltF4), and switch back to Blender.
In Blender, from Scripts Window, issue the Scripts → Update Menus command (figure 6.5). You will then find this script listed in Scripts → Object → Align view to selected. It is also placed in the 3D View window, as Object → Scripts → Align view to selected (figure 6.6) from which it is easily accessible.
|What about its documentation? Let's run Help → Scripts Help Browser from the User Preferences window. From the script groups, select Object → Align view to selected. The documentation screen will appear as shown in figure 6.7. Personally, I always create this documentation for my script commands. After a year, you can find that you remember nothing about tips and quirks for the script. Such documentation may not just help others, but may also help remind you!|
Appendix A. Detailed installation instructions:
In appendix A I will describe the install process in Windows for Python, wxPython and SPE. I only describe the install process in Windows since this is the operating system in which I work. You can get more detailed install instruction for any operating system supported by these programs at their respective websites.
Appendix A.1 - Python installation on Windows
Check the Blender console to see which which embedded Python version that it was compiled with. (It is printed when Blender starts) Now download the install program for the version of Python that Blender is using from http://www.python.org Figures A.1 through A.5 take you through a typical Python install on Windows.
As shown in figure A.2, I have removed the version number from the default name for the install directory. (The default install directory for Python v2.5 is C:\Python25). This is not a required step, just my personal preference. It was better in for tutorial to refer to a Python folder with no particular version number in its name otherwise it might create the false impression that you NEED Python 2.5 (which is not the case.) You could just as easily use Python v2.3 or 2.4 at this time, depending on the current requirements for wxPython 2.8
Appendix A.2 - wxPython installation
Now we will continue with the installation of wxPython. Go to http://wxPython.download.php and download the version of wxPython that corresponds with the version of Python that you just installed or was previously installed on your machine.
Figures A.6 through A.10 take you through a typical wxPython install on Windows.
Appendix A.3 - SPE installation
Version 0.8.4.d of SPE has been released and can be found at Stani's website. To install, download the file to your hard drive and extract using your favorite archiving tool to the site-packages/_spe folder in Python. (C:\Python\Lib\site-packages\_spe in windows).
Alternatively, you can also down load the most up to date, bleeding edge version from svn. (Please note that the svn version may not be as stable as the released version and you should use at your own risk!) I will describe the process of obtaining SPE from the SVN repository using rapidsvn. You can use any of the available SVN tools available. There is a short tutorial on using Tortoise SVNlocated here
I have used RapidSVN. Its install file can be downloaded from http://www.rapidsvn.org. I will skip the process of installing this tool - nothing special, just keep clicking Next until the end.
Then, to get the latest SPE SVN, open RapidSVN and select the Export command as in figure A.11. A dialog box will appear. Fill it as shown in figure A.12 (the _spe directory should not exist yet!). Then click the OK button to continue. After a while you will get a message showing successful completion of installation. (figure A.13) Of course, you can add manually the SPE shortcut to the Windows Start menu. Point it to the _spe\SPE.pyw file.
Appendix B. Content of the Command Scripts
The scripts that are used to run SPE and Winpdb from within Blender, spe_blender.py and winpdb_blender.py, were tested in a Windows environment. If they do not work on Linux, feel free to fix them. It would be also nice to let us know about the problems and the eventual solution. To make such modifications easier, I have discussed their content here.
Appendix B.1 "Stani's Python Editor" Command: spe_blender.py File
After removing all the historical comments and documentation strings, the core of this script is very simple:
import sys if sys.modules.has_key('_spe.SPE'): reload(sys.modules.get('_spe.SPE')) else: import _spe.SPE
This script simply forces all of the startup procedures in SPE.py file to run again, and then loaded for a second time. This is ensured by calling reload() function. The expression in the conditional statement just checks if SPE has been already loaded. After SPE is called for the first time, there is no SP module listed among the loaded modules therefore we call "import _spe.SPE" to load it. In all other cases this module should be reloaded, not imported
Appendix B.2 "Attach Winpdb debugger" Command: winpdb_blender.py File
This script, after removing all documentation strings is more complicated than spe_blender.py. It is because it performs more complicated action. Debugging of embedded script via Winpdb is implemented as a client-server communication. The server of debugging information is located inside the Blender embedded Python. It is brought to "life" by calling special function from rpdb2 module (it is a part of Winpdb). The client of debugging session is the Winpdb application, run as separate process, aside Blender. The Winpdb client process has to be attached to the server in Blender. To instruct Winpdb that, after opening, it has to attach immediately the Blender, some command line switches are used:
import os import sys import subprocess # # helper parameters - usually you do not need to change them: # WAIT_TIMEOUT = 15 #time that this script will wait for attaching a Winpdb PASSWORD = 'blender' #Winpdb requires a password between the client and #the server, so this is the one we will use. # # We will try to load rpdb2 from implicit path. It may work for a standalone # Winpdb installation. This way this script may work with newer version of # Winpdb, than this one that is shipped with SPE: # try:#looking for the default/standalone winpdb installation: import rpdb2 except ImportError: #we will try localize it within SPE directories: import _spe.plugins.spe_winpdb #import this, to use winpdb packed with SPE from rpdb2 import start_embedded_debugger, __file__ as rpdb2_file def debug(what): # # We will form the argument list for Winpdb invocation: # # # Argument 1: Python executable name. # (We cannot utilize here os.executable, because it returns "Blender.exe", # instead "python.exe)" # if os.name in ("nt","mac"): args=["pythonw"] # On Windows and Mac use this else: args = ["python"] #On Linux and other systems - standard python # # Argument 2: full path to Winpdb.py script name # args.append(os.path.join(os.path.dirname(rpdb2_file),"winpdb.py")) # # Argument 3: -a(ttach) specified script # args.append("-a") # # Argument 4: -p(assword): it is only available on nt systems. # if os.name == "nt": args.append("-p" + PASSWORD) # # Argument 5: name of the debugged script # args.append(what) # # Finally: run WinPdb... # if os.name == "nt": pid = subprocess.Popen(args) else: # # On Linux systems: we have to pass the password with stdin! # pid = subprocess.Popen(args, stdin = subprocess.PIPE, stdout = subprocess.PIPE) pid.stdin.write(PASSWORD + "\n") pid.stdin.flush() # # ....and let it to connect, waiting for <timeout> seconds: # start_embedded_debugger(PASSWORD, timeout = WAIT_TIMEOUT) # # Every script in Blender is represented by the same name: <string> # debug("<string>")
In this script there is the debug() function. It performs the main action: builds the argument list, and calls Winpdb (via subprocess.Popen object). Its last operation is to call the rpdb2.start_embedded_debugger() method. This method freeze whole Blender, waiting for the Winpdb to be attached. That's why it has to be the last line executed by this script. The code outside debug() function tries to import rpdb2 module (it is the server side of Winpdb debugger). It tries to find a standalone installation of the Winpdb, first (the "try" section). (This shortcut should work also with standalone Winpdb installation). If it does not succeed, the script executes the alternative - tries to find the Winpdb that is supplied with SPE. To be imported successfully, rpdb2 requires an implicit path to its files. It will not allow you to import it as _spe.plugins.winpdb.rpdb2. The call to import _spe.plugins.spe_winpdb internally calls import rpdb2 from inside SPE directories. At the end the debug() function is called. Its argument is "<string>", because every Python script in Blender run not from Text Editor window is represented by such name.
Appendix B.3 The Script Used in This Tutorial
Here is the code of the final version of the align_view.py script used in this tutorial. You can copy and paste fragments of its code, if you do not want to type them manually:
#!BPY #""" #Name: 'Align view to selected' #Blender: 245 #Group: 'Object' #Tooltip: 'Align view to selected object' #""" ####---Header------------------------------------------------------------------ __author__ = "Witold.Jaworski" __url__ = ("http://www.blender.org") __email__ = ("firstname.lastname@example.org") __version__ = "1.00" __bpydoc__ = """\ Use this script to align view to any of its 6 sides (left, right, front, ...). There is a standard Blender command - View\Align selected, but it always place the viewer perpendicular to object's XY plane. This script allows you to choose the side of selected object. """ ####imports----------------------------------------------------------------- import Blender ####constants--------------------------------------------------------------- MENU = """Object plane:%t |Top (XY)%x1 |Bottom (YX)%x2 |Front (XZ)%x11 |Rear (ZX)%x12 |Left (YZ)%x21 |Right (ZY)%x22 """ #menu option names (see the %xs from MENU-just to make the code more readable): TOP = 1 BOTTOM = 2 FRONT = 11 REAR = 12 LEFT = 21 RIGHT = 22 ####module functions----------------------------------------------------------- def ChangeViewTo(obj, option): """Changes current view Arguments: obj: selected object option: code for the plane (int), selected from popup menu by user """ rot = obj.getMatrix("worldspace").rotationPart() #axes of additional rotation: x = Blender.Mathutils.Vector(1,0,0)*rot #object's local x axis rx = Blender.Mathutils.RotationMatrix(-90,3,"r",x) #a rotation: a 1/4 around x z = Blender.Mathutils.Vector(0,0,1)*rot #object's local z axis rz = Blender.Mathutils.RotationMatrix(-90,3,"r",z) #a rotation: a 1/4 around z matrix = rot.invert() #rotation matrix for the view #we will add to it additional rotations, when needed if option == TOP:pass #object matrix is oriented on this plane-no change needed elif option == BOTTOM: matrix = rx*rx*matrix elif option == FRONT: matrix = rx*matrix elif option == REAR: matrix = rz*rz*rx*matrix elif option == LEFT: matrix = rz*rx*matrix elif option == RIGHT: matrix = rz*rz*rz*rx*matrix Blender.Window.SetViewQuat(matrix.toQuat()) Blender.Window.RedrawAll() def main(): """main procedure of this script It handles the interaction with the user """ if not Blender.Object.GetSelected(): Blender.Draw.PupMenu("Cannot align view:%t|There is no object selected") else: option = Blender.Draw.PupMenu(MENU) if option > 0 : ChangeViewTo(Blender.Object.GetSelected(),option) #let's run the whole thing: main()