<< Internal Scripts | Using Arexx >> |
Top: Documentation Library | Up: PageStream Scripting Documentation |
Using Python
Starting with the initial PageStream 4.1 Linux release, Python was added to PageStream's bag of tricks. The impetus was to provide the same scripting environment for all platforms to make user scripts the same on any platform PageStream supports. Previously the Amiga version had used ARexx and the Macintosh version AppleScript. While this was friendly for the platform it made quite a bit of work adding a new scripting engine for each platform and with Windows and Linux being added there had to be a better way.There are other cross-platform scripting languages -- the selection of Python was pragmatic and development driven: support was added in a single day. Since then the scripting interface has been modified to allow cleaner Python code. Though PageStream's scripting interface may not implemented in a Python-object fashion it works quite well.
Strictly speaking the scripting interface works with methods exposed to PageStream's internal macro language, although some commands make no sense in that context (for example, those that use variables -- a feature not present in the macro language). The macro language and ARexx share vary similar semantics, but Python just looks different.
The command names and even the templates are essentially the same. Where the documentation says NEWCHAPTER use the camel-cased NewChapter. If the command takes arguments, they are included in the parenthesis as quoted strings. Take care to include keywords as well, again quoted. SoPython:
newchapter 'Part Three' 7becomes
Python:
NewChapter("PartThree", 7)
CamelCasing is not actually required, but it does help readibility. PageStream actually lowercases all commands, keywords and variable names that are passed to it. |
So much for issuing commands, but what about getting values back from them? All PageStream commands return a list. At a minimum there are two keys in the list, .result and .error. If the command issued included stem variables then those will be included as well. A return list might look something like:Python:
{'.error': 1, '.result': 0, 'stem': {'width': 8.5, 'sides': 'DOUBLE', 'orientation': 'PORTRAIT', 'height': 11.0}}The common keys and their meanings are as follows:
.error This is 1 if there is no error, otherwise it is zero
.result This is the result code for the command; the meaning depends on the command.
.errno This key is present if there is an error and is the number for the error. For example, CurrentWindowPath errno 1001 means that there is no window to have a current window path.
.errstr This key is present if there is an error and is the text string for the error. For example, CurrentMasterPage errstr 'No Master Page' means that there is no master page for the current document.To issue PageStream commands you must import them first. The library is, unsurprisingly, called PageStream.
Python:
from PageStream import *Because PageStream implements Python by embedding the interpreter in its own executable instead of providing a standalone library you can't import PageStream except from within PageStream. This makes development and testing a bit awkward.
One way of dealing with this on Linux is to redirect PageStream's output into a log file. Alter the script that starts PageStream so that it includes the following:
Code:
echo "----" >> ~/PgS.log
echo `date` >> ~/PgS.log
$PGSPATH/PageStream5 >> ~/PgS.log 2>&1This creates a log file in your home directory named PgS.log (or appends to it if a file by that name already exists). Marking PageStream's startup and putting in a date/time stamp helps make the log file more readable. The end result is a trace of PageStream's output, both stdout and stderr. However, the file only gets written to when the output buffer gets flushed. The only certain way of flushing the buffer is to close PageStream, but often a script that creates a non-critical error will work as well.
Because the shells provided by Microsoft don't show the output from PageStream on Windows it is recommended to use a replacement shell like msys instead.
- OS X: bundled with the OS
- Linux: depends on the distro, but generally is included
- Windows: add on, see below
- Amiga: add on(1), http://www.monkeyhouse.eclipse.co.uk/amiga/python
The main Python site is http://www.python.org -- follow the download link. There are source archives as well as a Windows installer.
The layout of a window or dialog box is determined by a resource file. Such files have the .rsc extension and, being plain text, can be edited with any text editor.(2) If characters outside the standard 7-bit ASCII are needed make sure to use an editor that will save the file with UTF-8 encoding.
All considerations of white space are solely for readability. PageStream itself does not care about white space. A resource file consists of string table, requester and icon definitions. String tables, string items, icons, requesters and the objects in a requester are each identified by a number. In the case of string tables, icons and requesters the number must be unique in the file for objects of that type. Other objects must be unique in their respective container, irrespective of type.
String Tables
The purpose of a string table is to provide for localization. Ideally, all text associated with a resource is placed in a resource file string table rather than in code. This is true even for scripts. It becomes substantially more difficult to localize text if this is not done. By convention string tables are placed first in a resource file. This allows ready location of all strings for translation.String tables consist of the string table declaration followed by a series of string item declarations. The string table ends when the next string table starts, a requester is declared, or the file ends. A string table that is associated with a requester will usually be assigned a unique ID one after the requesters. For example, if the requester is ID 200 then its string table would be 201.
Code:
STRINGTABLE #201
STRINGITEM #1 :"Some text for requester 200"
STRINGITEM #2 :"Some more text"
STRINGITEM #3 :"And even more text"Requesters
Requesters provide resizeable and scalable graphical user interface objects. The layout rules to get the desired result can be a little tricky -- if a requester does not behave as expected when resized take a careful look at how you specify its layout. The template for a requester declaration is as follows:REQUESTER #<ID> [W#<Width> H#<Height>] [L:"<Title>"] [:"path/to/help.html"]
Containers
There are three basic containers for controlling layout: boxes, grids and button groups. The end of a container is marked with the END keyword and the contents of a container are indented. As containers are meta information belonging to a requester and not themselves objects they do not have IDs.Boxes can be either horizontal or vertical, the keyword being HBOX and VBOX, respectively. Whether or not there is white space padding round the container is controlled by the MARGIN | NOMARGIN keywords.
Grids provide a flexible grid of cells with the top left corner having coordinates of 0,0. Objects contained by a grid specify their position in it by putting the cell boundaries after the object's ID using the following template. L#<left> R#<right> T#<top> B#<bottom>
Code:
REQUESTER #101 L:"Sample Requester"
VBOX
GRID NOMARGIN
END
BGROUP
END
ENDBasic Objects
There are four basic objects: string boxes, check boxes, buttons and popup menus. As each is an object it must have an ID that is unique to the requester. The template is <ObjectType> #<ID> [<Grid Coordinates>] L:"<Label>". The string box has an additional parameter W#<Width> that can be used to set the maximum string length to be input.Code:
STRING #10 L#1 R#3 T#0 B#1 L:"Input text"
CHECKBOX #11 L#0 R#1 T#1 B#2 L:"Check me"
BUTTON #12 L#2 R#3 T#1 B#2 L:"Click me"
POPUP #13 L#1 R#3 T#2 B#3 L:"Select one"
A button can have an optional keyword to specify that it is a special button. The keyword ISOK causes the "OK" icon (a green checkmark) to be added to the button. ISCANCEL causes the "Cancel" icon (a red X) to be added to the button. [note=sidebar]Keyboard shortcuts can be set for any object that has a label by putting an underscore before the shortcut character. For example, STRING #10 L:"Input _text" would set the letter 't' as the shortcut for string box number 10.
Code:
BUTTON #9 ISCANCEL L:"Cancel"
BUTTON #1 ISOK L:"Accept"
[/note]Popup Menus
A popup is empty until given some content. A list can be defined in the resource file or added by the program. To define a list in the resource file indent from the POPUP declaration to show that the list is contained by the popup menu. A list declaration is a container the end of which is marked by the ENDLIST keyword. Everything in the list declaration should be a list item. The template for a list item is LISTITEM #<ID> :"<Text in the popup>". The ID for a list item only needs to be unique in that list and is the value associated with the entry.Code:
LIST
LISTITEM #1 :"Apples"
LISTITEM #2 :"Oranges"
LISTITEM #3 :"Pears"
ENDLISTOther Objects
There are a variety of additional objects available as well.Help Button
HELP #<ID> LABEL
To put a help button on the requester you must specify a unique ID. If the button is clicked it will attempt to open a web browser and load the URL specified by the requester for its help file. The URL is always relative to the PageStream help file directory.Code:
HELP #999 LABELDisplay Text
DISPLAY #<ID> [Grid coordinates] [H#<Height>] [RECESSED] [CENTER] [L:"<Label>"] S:"<Text to be displayed>"
This object puts text in the requester. It can be framed, inset, etc.
Code:DISPLAY #10 L#0 R#4 T#0 B#1 H#4 S:"Some longer text that is displayed in the requester without having a scroller or any border"Toggle
TOGGLE #<ID> I#<number>Mini Menu
MINIMENU #<ID>
This is the kind of menu found in the Edit Palette for selecting the type of corner used on a box. The options displayed are either added to the mini menu programmatically or via a list container.Code:
MINIMENU #30 L#2 R#3 T#0 B#1
LIST
LISTITEM #1 :Load
LISTITEM #2 :Save
ENDLIST
List View
LISTVIEW #<ID> [H:<Height>] [L:"<Label>"]
Provides a scrolling view port on a list. The list can be declared in the resource file or added programmatically.Slider
SLIDER #<ID> M#<Maximum Value> [L:"<Label>"]
This is used to put a slider that represents a value from zero to the specified maximum.IconsAn icon consists of a 1-bit mask and RGB color data. Because an icon is an object it must have a unique identifier. By convention it is numbered following the requester it is associated with. For example, an icon for requester 100 might have ID 110. The mask is declared using the template ICONMASK <width> <height> and the color data is declared using ICONPART <bits per pixel> <width> <height>. In both cases the actual data is supplied four bytes per line.Code:
ICON #100
ICONMASK 16 16
0000
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
7FFE
0000
ICONPART 1 16 16
0000
7FFE
4202
4202
7FFE
4202
56AA
4202
6B56
4202
56AA
4202
6B56
4202
7FFE
0000
For a script to have anything more than a simple pre-set GUI (such as those provide by AlertRequester) it must use a resource file. The resource file contains the definition of one or more requesters. To use a requester the resource file containing it must be opened for use with the OpenResource command. Before using the resource it is important to verify that it was successfully opened. The unique identifier for the resource is in the .result value. This will be 0 if the resource file could not be opened.Python:
rc = OpenResource("RequesterExample")
if rc['.result'] == 0:
AlertRequester(AlertType_Error, "RequesterExample.rsc missing", "OK")
else:
# the code using the requester
The resource file must be in the same directory as the script and the extension is not specified: PageStream automatically adds '.rsc' to the name. Any values that need to be read from the string tables in the resource file can now be loaded with the GetResource command. Requester definitions can also be loaded with the CreateRequester command.
Code:
reqH = CreateRequester(rscH, 100)['.result']Any lists that will be set programmatically can now be done so. A special case of this is getting the list of available languages from PageStream with the CreateLanguageEngineList command. Although that command can be used at any time it is usually used to set a list in the requester. Note the use of SetControlAttr to set the currently selected language to a specific value.
Code:
lelistH = CreateLanguageEngineList()['.result']
SetControlAttr(reqH, 11, ControlAttr_List, lelistH)
SetControlAttr(reqH, 11, ControlAttr_String, "American")In general, set any control in the requester as desired to complete setup. When everything is set use DoRequester to make the requester visible to the user. The DoRequester() command is a blocking command. Script execution stops until the requester is closed, the return value being the ID of button that was clicked.
Code:
buttonid = DoRequester(reqH)
if buttonid == 1:
# do stuff
elif buttonid == 2:
# do other stuff
else:
# do something elseTo get information out of the requester, such as text typed into a string, use the GetControlAttr command.
1. Amiga Python does not work for Python scripting as presented here (PageStream uses an embedded interpreter that requires an external library -- this is not currently supported by Amiga Python).
2. Although you can technically edit the rsc files that come with PageStream it is not recommended as an invalid rsc file will result in undefined behavior.
Using Python by Tim Doty Chapter url:PGScmd/Cpython
created:2006-03-31 14:53:35 last updated:2006-08-08 16:49:35
Copyright © 1985-2024 GrasshopperLLC. All Rights Reserved.
User Contributed Comments For Using Python | sign in to add a comment |
Tim Doty wrote... | 2006-04-25 04:38:41 |
From my scripting notes: ================================================================================ Problem: calling sys.exit() exits the script AND PageStream so how do you exit a script? Solution: there are several ways to do this, but the best ways revolve around declaring a main() function. The main() function itself is called by a simple construct that makes it safe to import the script file as a module: Code: def main():
... code 1 ... if condition1: ... code 2 ... if condition2: ... code 3 ... if __name__ == "__main__": | |
Tim Doty wrote... | 2006-04-25 05:02:54 |
Again from my notes: Global variables UnboundLocalError: local variable 'my_variable' referenced before assignment So, there are three ways that file-scope variables can be used. 1. Read Only 2. Global Code: global my_variable 3. Pass value | |
Tim Doty wrote... | 2006-04-25 05:05:11 |
This is really a Python issue, but it is an interesting problem that I had some difficulty finding a good answer for (the solution is obvious for those familiar with Python, but just coding for PgS doesn't make that so). Calling a function by composed string Code: >>> def my_func(): >>> print "Hello World" >>> >>> my_string = "my_func" >>> my_string() Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: 'str' object is not callable However, all local functions and variables are returned in a list by the locals() function and all global functions and variables are returned in a list by the globals() function. To call a function with a composed string name all you have to do is the following: Code: >>> locals()[my_string]() | |
Henry G Belot wrote... | 2006-04-25 12:25:29 |
This would be a good place to tell people where to get Python. There is a reference further down in Tim's comments to the main Python site. As I remember, Python for the Amiga is on a different site and I'm not sure there's a link at the Python site. A line or two about the pros and cons of using either of the scripting languages as opposed to the internal macro capability would also be appropriate. I would also add an explicit caveat that the documentation will not teach someone either language. HB | |
Deron Kazmaier wrote... | 2006-09-14 09:25:14 |
New in 5.0.2.11: | |
Tim Doty wrote... | 2007-07-05 05:50:29 |
Translating Resource Files If you've gone to all the trouble of creating a resource file for your script you may want to take advantage of the localization facilities provided by PageStream. Here is how you do it. Translated Resource File Format Great, but you are curious about the format used by the translation files? Basically its a streamlined version of the regular resource file. Here's how it goes: | |
Tim Doty wrote... | 2007-07-05 14:32:39 |
One difficulty with developing PageStream scripts is that you have to fore go the Python interactive shell that lets you try things out so easily. Or do you? Many things can still be worked out in the interactive shell, but if your code depends on PageStream to do anything then you are stuck. Or are you? It depends on just how dependent your code is. Ideally your code will be modular. Along with other benefits if a module doesn't need to make any PageStream function calls simply don't import PageStream. This allows you to import the module into the Python command shell for testing and debugging. And even if some parts of the module must have the PageStream functions you can still test in the Python command shell if you import PageStream like this: Python: try:
from PageStream import * except ImportError: print "WARNING: PageStream dependant functions will not work" Another option is to try the Console script from http://www.morfarpottery.com/PageStream/scripts.php | |
Tim Doty wrote... | 2008-03-22 14:21:57 |
Further options for an element in a resource file: alignment For example a DISPLAY element can have the alignment specified as LEFT | CENTER | RIGHT and the flag RAISED | RECESSED is used to make it appear raised or recessed. Additional elements include ARROW. Arrow types include LEFTRIGHT, UPDOWN, RUPDOWN, ANGLE. In each case a pair of arrows are shown with the indicated presentation (left/right or up/down). The ANGLE type is for the rotating arrows as are used to show rotation. I'm not sure what difference there is between UPDOWN and RUPDOWN -- presumably one increases with UP while the other decreases. | |
Tim Doty wrote... | 2010-01-07 10:51:29 |
This probably shouldn't be buried in a comment, but as it does not appear to be documented on this site: If you have Python installed and PageStream is not recognizing that fact (the "Play External Script" menu item is ghosted) then you most likely have to manually specify the version of Python to use. This isn't a pretty way to do it, but it does work to get around a limitation of how Python libraries have to be opened by the application. This can also come in handy if you have multiple versions of Python installed on your system and you need to force PageStream to use a particular version. What you have to do is add a line to your prefs file. On linux this is ~/.PageStream5/PageStream5.prefs. On OS X the preferences file will be under ~/Library/Application Support/PageStream5. On Windows it will be in your user profile -- off hand I don't know the path. The line is as follows: PYTHONLIBRARY <python library/dll> <API version number> For example, on linux this might be: PYTHONLIBRARY libpython2.4.so 1012 or PYTHONLIBRARY libpython2.6.so 1013 Note: make sure you include the correct library. E.g., /usr/lib/libpython2.6.so.1 would be libpython2.6.so.1 -- in particular the library filename may be longer than indicated above. | |
T.J. Zweers wrote... | 2010-01-07 14:46:00 |
Tim said: This where it will be: C:\Documents and Settings\AccountName\Application Data\PageStream5 (at least on Windows XP). AccountName is the name you use to log in if you have more than one account. For Windows the prefs file is called: PageStream5.ini. | |
T.J. Zweers wrote... | 2010-03-28 07:18:16 |
Adding this: 'Users' can be a different name in your language (Gebruikers in Dutch), but if you click (left mouse button) in the Windows Explorer bar, it is English. | |
User Contributed Comments For Using Python | sign in to add a comment |
<< Internal Scripts | Using Arexx >> |
Top: Documentation Library | Up: PageStream Scripting Documentation |