Transitioning from Vectorscript Pascal to Vectorscript Python has its challenges. Here I note down the difficulties I encounter as they come, together with the solution. What troubles me will likely trouble all others.
Note: As of today, the wiki doesn't accept external links for safety reasons, which are thus not clickable.
As of this writing, Vectorworks requires Python 3.x. MacOS X before 10.15 ships with Python 2.x. VW delivers the right Python, so you don't need to do anything special if there are no external, vw-unrelated reasons to do so. Should you wish to modify the Python installed on your machine you can proceed as follows, but this won't modify the shipped VW Python. For example, you might want to do some terminal tutorials.
- Launch the Terminal
- Type:
If there is an error, you should install Python 3 and configure it.
python3 --version - Follow the instructions on installpython3.com/mac/.
This document is very complete and leads you step by step through the rather cryptical configurations. During this process you will install XCode and Homebrew through the terminal.
Warning: For some reason XCode wouldn't install on my MacOS X.14. After various hours of fumbling, I gave up and went straight to the official Python 3 installer, available at python.org. After that I proceeded with the configurations as described in installpython3.com/mac/ and all seems well enough.
I tried using Aptana but couldn't configure it. Then I found at Computerworks excellent instructions by Oliver Daus for Visual Studio Code: (German) www.vectorworksforum.eu/topic/14087-entwicklungsumgebung-für-vectorworks-python-plug-ins/
- Download Visual Studio Code from code.visualstudio.com and install it.
- Install the Python extension: launch Visual Studio Code, click on Extensions (
shift + cmd + X), search forms-python, click on install Python. - Create a script library folder for all your Python tools and commands. I named mine
_VS. - In this script library place a file called
vs.pycontaining all the Vectorscript calls. You can find this file in the SDK. - In Visual Studio Code, open the Settings. In Extensions:
Pylance > Python › Analysis: Extra Paths: add the path to the above-mentioned script library folder (_VS).- Python > Auto Complete Extra Paths > Edit Settings Json: enter the path to the script library folder, it will look roughly like this:
"python.autoComplete.extraPaths": [
"/Users/userName/path/to/my/scriptLibrary/_VS"
],- Place in the script library folder a
vs.pyfile. It contains the actual list of Vectorscript routines. This file will also allow for intelligent hints (Intellisense) while using an Editor capable of it. You can download the file from the SDK: www.vectorworks.net/support/custom/sdk - In Vectorworks > Script Editor > Script Options: enter the path to your script library folder.
Intellisense from Visual Studio Code:
Perhaps the largest source of error while transitioning to Python are the deep differences in variables.
| Description | Vectorscript Pascal | Vectorscript Python |
|---|---|---|
| Returning Values | Results left, VARs and arguments rightFUNCTION ActiveClass : STRING;classN := ActiveClass;<br>FUNCTION GetCustomObjectInfo( VAR objectName :STRING; VAR objectHand :HANDLE; VAR recordHand :HANDLE; VAR wallHand :HANDLE) : BOOLEAN;ok := GetCustomObjectInfo( objectName, objectHand, recordHand, wallHand );PROCEDURE HMove( objectHand :HANDLE; xOffset :REAL; yOffset :REAL);HMove( objectHand, xOffset, yOffset ); |
Results left, VARs left, arguments rightdef vs.ActiveClass(): return STRINGclassN = vs.ActiveClass()def vs.GetCustomObjectInfo(): return (BOOLEAN, objectName, objectHand, recordHand, wallHand)ok, objectName, objectHand, recordHand, wallHand = vs.GetCustomObjectInfo()def vs.HMove(objectHand, xOffset, yOffset): return None<br><br>vs.HMove(objectHand, xOffset, yOffset) |
| Variable Attributes discovered by P. Winkler 2017 |
no | built in in VWh = vs.FSActLayer()print(h.type)print(h.locked)print(h.name)print(h.selected)print(h.prev)print(h.next)print(h.parent) |
| Variable scope | Global wins over local: - Variables must be declared - Subroutines "see" their own variables and those of any parent function/procedure where they are contained. { GLOBAL ACCESS }PROCEDURE Main; VAR { good praxis: label globals with "g" } gIndex, gNum : INTEGER; PROCEDURE Increment; BEGIN gNum := gNum +1; SysBeep; END;BEGIN gNum := 10; FOR gIndex := 1 TO 10 DO Increment; AlrtDialog(Concat(gNum));END;Run(Main); |
Local wins over global: - Variables must NOT be declared - Subroutines create automatically a local instance of any used variable. # LOCAL ACCESSdef Increment(): gNum +=1 vs.SysBeepgNum = 10for gIndex in range(1, 10): Incrementvs.AlrtDialog(str(gNum))# returns 10! The global var didn't set# GLOBAL ACCESS: CORRECTdef Increment(): global gNum gNum +=1 vs.SysBeep()gNum = 10for gIndex in range(0, 10): Increment()vs.AlrtDialog(str(gNum))# returns 20# TRY GLOBAL ACCESS: WRONGdef Increment(): global gNum gNum +=1 vs.SysBeep()# no init!for gIndex in range(0, 10): Increment()vs.AlrtDialog(str(gNum))Error Message: NameError: global name 'gNum' is not defined # TRY GLOBAL ACCESS: WRONGglobal gNum # wrong place!def Increment(): gNum +=1 vs.SysBeep()gNum = 10for gIndex in range(0, 10): Increment()vs.AlrtDialog(str(gNum))Error Message: UnboundLocalError: local variable 'gNum' referenced before assignment |
| NIL handles | h <> NIL |
Recommended:h is Noneh is not NoneNot recommended: h != Noneh != vs.Handle()See: PEP 8 |
| Fetching Plug-in Parameters | Direct, not case sensitive:MoveTo(PCONTROLPOINT01X, PCONTROLPOINT01Y);LineTo(PCONTROLPOINT02X, PCONTROLPOINT02Y); |
Prefixed with 'vs', case sensitive: Correct: vs.MoveTo(vs.PControlPoint01X, vs.PControlPoint01Y)vs.LineTo(vs.PControlPoint02X, vs.PControlPoint02Y)Wrong: vs.MoveTo(vs.PCOntrolPoint01X, vs.PControlPoint01Y)vs.LineTo(vs.PcontrolPoint02X, vs.PControlPoint02Y) |
| Using units | Yes:GetSymLoc(symH, c.x, c.y);MoveTo(c.x, c.y);Line(1m, 0); |
Needs conversion:c = vs.GetSymLoc(symH)vs.MoveTo(c[0], c[1])vs.Line(Str2Num('1m'), 0) |
| Vectors, Points | Can be manipulated in place:GetSymLoc(symH, c.x, c.y);c.x := c.x +1m; |
Is Tuple: An ordered list whose items are unchangeable c = vs.GetSymLoc(symH)c[0] = c[0] +1m# error! |
| Colors | Color Index:SetPenFore(h, RGBToColorIndex(65535, 0, 0));PenFore(RGBToColorIndex(65535, 0, 0));RGB: SetPenFore(h, 65535, 0, 0); |
Color Index:vs.SetPenFore(h, vs.RGBToColorIndex(65535, 0, 0))RGB in Tuple: vs.SetPenFore(h, (65535, 0, 0))Hex in Tuple: vs.SetPenFore(h, (0xFFFF, 0, 0))Warning: vs.PenFore((65535, 0, 0)) correctvs.PenFore(65535, 0, 0) fails (no error message!) |
| Description | Vectorscript Pascal | Vectorscript Python |
|---|---|---|
| Includes/Import Load libraries of code |
$INCLUDE libraryFolder\libraryFile.vss Note: the path to the vss/px file is relative to the running .vso/.vst/.vsm plug-in file.
In the example in the screenshot, the file z_Ramp.px is located 2 folders higher ( External libraries: not possible |
Python calls Includes "imports". It searches for imports in the current directory, then in dedicated directories, if any (Script Options). For the current directory, Python understands the folder of the running .vso/.vsm/.vst file.
import main import vs But not: import vs, math # not recommended Absolute path: import mypkg.sibling Relative path: from . import sibling See more in: PEP 8 Imports Note: the paths listed through the Script Options dialog are valid for all plug-ins. One might be misled into thinking that the list affected only one plug-in.
External library: include + name of the chosen library import sys VS API: you must always include the VS API or you won't be able to use it. This file will also allow for intelligent hints while using an Editor capable of it. Download it from the SDK: Vectorworks SDK
import vs
Intellisense from Visual Studio Code:
|
| Encryption See encryption for more information. |
{$INCLUDE ..\..\_VS_includes\_common\Utils.px}
|
For encryption in Python, there are difficulties. See instructions from Vlado on the Techboard, search for "problems-encrypting-a-python-script" (at the moment we cannot add external links to the present wiki). |
| Python Version | - |
import sys |
| Python Caching Some caching prevents your script from reflecting changes: |
- |
varPersistentPythonEngine = 412 { Boolean }
|
Lists are powerful in Python. Below are some fascinating list manipulations. They remind me of AppleScript:
months = "Jan Feb Mar Apr May Jun Jul"
months = months.split() # no splitter defined and it will use the empty space --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul']
months[2] # --> 'Mar' note that the index is 0-based
months2 = "Jan, Feb, Mar, Apr, May, Jun, Jul"
months2.split(', ') # --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] use comma and empty space as splitter
months.append('Jul') # --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] append adds an item to a list
months.pop() # --> 'Jul' pop fetches the last item of a list
', sunny '.join(months) # --> ', sunny Jan, sunny Feb, sunny Mar, sunny Apr, sunny May, sunny Jun, sunny Sep'
'-'.join(months[1:3]) # --> 'Feb-Mar'
del months[2] # --> ['Jan', 'Feb', 'Apr', 'May', 'Jun', 'Jul']
months = {1: 'Jan', 2: 'Feb', 3: 'Mar'} # --> {1: 'Jan', 2: 'Feb', 3: 'Mar'}Python Error Messages:
BaseExceptions:
- SystemExit
- KeyboardInterrupt
- GeneratorExit
- Exception
- StopIteration
- ArithmeticError
- FloatingPointError
- OverflowError
- ZeroDivisionError
- AssertionError
- AttributeError
- BufferError
- EOFError
- ImportError
- LookupError
- IndexError
- KeyError
- MemoryError
- NameError
- UnboundLocalError
- OSError
- BlockingIOError
- ChildProcessError
- ConnectionError
- BrokenPipeError
- ConnectionAbortedError
- ConnectionRefusedError
- ConnectionResetError
- FileExistsError
- FileNotFoundError
- InterruptedError
- IsADirectoryError
- NotADirectoryError
- PermissionError
- ProcessLookupError
- TimeoutError
- ReferenceError
- RuntimeError
- NotImplementedError
- SyntaxError
- IndentationError
- TabError
- IndentationError
- SystemError
- TypeError
- ValueError
- UnicodeError
- UnicodeDecodeError
- UnicodeEncodeError
- UnicodeTranslateError
- UnicodeError
- Warning
- DeprecationWarning
- PendingDeprecationWarning
- RuntimeWarning
- SyntaxWarning
- UserWarning
- FutureWarning
- ImportWarning
- UnicodeWarning
- BytesWarning
- ResourceWarning





