User:CBM-c-/VS-Py Rosetta Stone: Difference between revisions
m (→VS - Py: fix) |
(split table, expand content) |
||
Line 5: | Line 5: | ||
= VS-Python Rosetta Stone = | = VS-Python Rosetta Stone = | ||
Transitioning from Vectorscript Pascal to Vectorscript Python has its challenges, | 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, which are thus not clickable. | ; Note: as of today the wiki doesn't accept external links for safety reasons, which are thus not clickable. | ||
Line 33: | Line 33: | ||
== VS - Py == | == VS - Py == | ||
=== Syntax Pitfalls === | |||
{| class="wikitable" | {| class="wikitable" | ||
! style="width: | ! style="width:20%"| Description | ||
! style="width: | ! style="width:40%"| Vectorscript Pascal | ||
! style="width: | ! style="width:40%"| Vectorscript Python | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
Line 51: | Line 54: | ||
: [[file:PythonIndent2.png]] | : [[file:PythonIndent2.png]] | ||
Error Message: unexpected indent | Error Message: unexpected indent | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| ''' | | '''Semicolon''' | ||
| ''' | | '''Always needed:''' | ||
: <code>AlrtDialog('test 1') <br>AlrtDialog('test 2') { error }</code> | : <code>AlrtDialog('test 1') <br>AlrtDialog('test 2') { error }</code> | ||
: <code>AlrtDialog('test 1'); AlrtDialog('test 2'); { OK }</code> | : <code>AlrtDialog('test 1'); AlrtDialog('test 2'); { OK }</code> | ||
: <code>AlrtDialog('test 1') AlrtDialog('test 2') { error }</code> | : <code>AlrtDialog('test 1') AlrtDialog('test 2') { error }</code> | ||
| ''' | | '''Only needed for multiple statements on one line:''' | ||
: <code>vs.AlrtDialog('test 1') </br>vs.AlrtDialog('test 2') # OK</code> | : <code>vs.AlrtDialog('test 1') </br>vs.AlrtDialog('test 2') # OK</code> | ||
: <code>vs.AlrtDialog('test 1'); vs.AlrtDialog('test 2') # OK</code> | : <code>vs.AlrtDialog('test 1'); vs.AlrtDialog('test 2') # OK</code> | ||
Line 64: | Line 68: | ||
Error Message: SyntaxError: invalid syntax | Error Message: SyntaxError: invalid syntax | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| '''Case sensitivity''' | | '''Case sensitivity''' | ||
| '''Not case sensitive:''' | | '''Not case sensitive:''' | ||
: <code>AlrtDialog('test'); { OK }</code> | |||
: <code>alrtDialog('test'); { OK }</code> | |||
: <code>alrtdialog('test'); { OK }</code> | |||
: <code>ALRTDIALOG('test'); { OK }</code> | |||
| '''Case sensitive:''' | | '''Case sensitive:''' | ||
: <code>vs.AlrtDialog('test') # OK </code> | |||
: <code>vs.alrtDialog('test') # error</code> | |||
: <code>vs.alrtdialog('test') # error</code> | |||
: <code>vs.ALRTDIALOG('test') # error</code> | |||
Error Message: AttributeError: 'module' object has no attribute 'vs.ALRTDIALOG' | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| ''' | | '''Brakets''' | ||
: don't forget in python the empty brakets for routines without parameters, | : don't forget in python the empty brakets for routines without parameters, or it will rise cryptical errors. | ||
| ''' | | '''No brakets''' | ||
: <code>FSActLayer; { no parameters: brakets not needed }</code> | |||
: <code>MySubroutine;</code> | |||
| ''' | | '''Brakets''' | ||
: <code>vs.FSActLayer()</code> | |||
: <code>MySubroutine()</code> | |||
Error Message: - none! be careful! - | |||
|- style="vertical-align: top;" | |||
| '''FOR statements''' | |||
| '''Runs including last value:''' | |||
<code lang="pas"> | |||
{ runs 3 times! 1, 2 and 3 } | |||
FOR i := 1 TO 3 DO | |||
AlrtDialog(Concat(i)); | |||
</code> | |||
| '''Runs excluding last value:''' | |||
<code lang="py"> | |||
# runs 2 times! 1 and 2 | |||
for i in range(1, 3): | |||
vs.AlrtDialog(str(i)) | |||
</code> | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| ''' | | '''Concatenate text''' | ||
: | | '''Supports implicit conversion:''' | ||
: Both [[VS:Concat| Concat]] and [[VS:Message| Message]] support multiple variable types and convert them into string. | |||
: <code>t := Concat(10, ' fingers'); { OK }</code> | |||
| | : <code>Message(10, ' fingers'); { OK }</code> | ||
: <code>AlrtDialog(Concat(10, ' fingers')); { OK }</code> | |||
| '''Doesn't support implicit conversion:''' | |||
: For example an integer won't automatically be converted into string. Wrap it in [[VS:Concat| vs.Concat]] or [[VS:Message| vs.Message]], alternatively perform the needed conversion. | |||
: <code>t = 10 + ' fingers' # error</code> | |||
: <code>t = vs.Concat(10, ' fingers') # OK</code> | |||
: <code>vs.Message(10, ' fingers') # OK</code> | |||
: <code>vs.AlrtDialog(str(10) + ' fingers') # OK</code> | |||
: <code>vs.AlrtDialog(10 + ' fingers') # error </code> | |||
Error Message: TypeError: unsupported operand type(s) for +: 'int' and 'str' | |||
|} | |||
=== Variable Pitfalls === | |||
{| class="wikitable" | |||
! style="width:20%"| Description | |||
! style="width:40%"| Vectorscript Pascal | |||
! style="width:40%"| Vectorscript Python | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| '''Setting VARs, returning Values''' | | '''Setting VARs, returning Values''' | ||
| '''variable returned divided from VARs set''' | | '''variable returned divided from VARs set''' | ||
<funcDef lang="vs"> | |||
FUNCTION GetCustomObjectInfo( VAR objectName : STRING; VAR objectHand : HANDLE; | |||
VAR recordHand : HANDLE; VAR wallHand : HANDLE) : BOOLEAN; | VAR recordHand : HANDLE; VAR wallHand : HANDLE) : BOOLEAN; | ||
</funcDef> | |||
<code lang="pas"> | |||
ok := GetCustomObjectInfo( objectName, objectHand, recordHand, wallHand ); | ok := GetCustomObjectInfo( objectName, objectHand, recordHand, wallHand ); | ||
</code> | |||
| '''variable returned and VARs set before routine''' | | '''variable returned and VARs set before routine''' | ||
<funcDef lang="py"> | |||
def vs.GetCustomObjectInfo(): | def vs.GetCustomObjectInfo(): | ||
return (BOOLEAN, objectName, objectHand, recordHand, wallHand) | return (BOOLEAN, objectName, objectHand, recordHand, wallHand) | ||
</funcDef> | |||
<code lang="py"> | |||
ok, objectName, objectHand, recordHand, wallHand = vs.GetCustomObjectInfo( ) | ok, objectName, objectHand, recordHand, wallHand = vs.GetCustomObjectInfo( ) | ||
</code> | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
Line 152: | Line 199: | ||
Run(Main); | Run(Main); | ||
</code> | </code> | ||
| | |||
'''Local wins over global:''' | | '''Local wins over global:''' | ||
* Variables must NOT be declared | * Variables must NOT be declared | ||
* Subroutines create automatically a local instance of any used variable. | * Subroutines create automatically a local instance of any used variable. | ||
Line 217: | Line 264: | ||
Error Message: NameError: global name 'gNum' is not defined | Error Message: NameError: global name 'gNum' is not defined | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| ''' | |||
| ''' | | | ||
; NIL handles: | |||
| | |||
h <> NIL | |||
| | |||
| ''' | h != None | ||
h != vs.Handle() # not inited instance of a handle, how cryptic | |||
|- style="vertical-align: top;" | |||
| '''Fetching Plug-in Parameters''' | |||
| '''Direct:''' | |||
MoveTo(PCONTROLPOINT01X, PCONTROLPOINT01Y); | |||
LineTo(PCONTROLPOINT02X, PCONTROLPOINT02Y); | |||
| '''Prefixed with ''vs'':''' | |||
vs.MoveTo(vs.PControlPoint01X, vs.PControlPoint01Y) | |||
vs.LineTo(vs.PControlPoint02X, vs.PControlPoint02Y) | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| '''Colors''' | | '''Colors''' | ||
| | | | ||
; Color Index: | |||
: <code>SetPenFore(h, RGBToColorIndex(65535, 0, 0));</code> | |||
: <code>PenFore(RGBToColorIndex(65535, 0, 0));</code> | |||
; RGB: | |||
: <code>SetPenFore(h, 65535, 0, 0);</code> | |||
| | | | ||
; Color Index: | |||
: <code>vs.SetPenFore(h, vs.RGBToColorIndex(65535, 0, 0)) </code> | |||
; RGB in Tuple: | |||
: <code>vs.SetPenFore(h, (65535, 0, 0)) </code> | |||
; Hex in Tuple: | |||
: <code>vs.SetPenFore(h, (0xFFFF, 0, 0))</code> | |||
Warning: don't forget the brakets: | ; Warning: don't forget the brakets: | ||
: <code>vs.PenFore((65535, 0, 0)) </code> correct | |||
: <code>vs.PenFore(65535, 0, 0) </code> fails | |||
Error Message: - none! be careful! - | Error Message: - none! be careful! - | ||
|} | |||
=== Includes / Imports === | |||
{| class="wikitable" | |||
! style="width:20%"| Description | |||
! style="width:40%"| Vectorscript Pascal | |||
! style="width:40%"| Vectorscript Python | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| '''Includes/Import''' | |||
Load libraries of code | |||
| | |||
; Custom (own) Libraries: | |||
:* use the term ''$INCLUDE'' | |||
:* pass the appropriate path to your code and/or code libraries | |||
$INCLUDE libraryFolder\libraryFile.vss | |||
$INCLUDE libraryFolder\libraryFile.px | |||
[[File:IncludeVS.png| 500px]] | |||
; External libraries: not possible | |||
| | |||
; Custom (own) Libraries: You must set up one or more environmental paths from which all active plug-ins will resolve includes | |||
:* choose a library folder with your code and/or libraries in the Plug-Ins ''Script Options'' | |||
:* use the term ''Import'' | |||
; Note: the paths listed through the ''Script Options'' dialog are valid for ''all'' plug-ins. One might be mislead into thinking that the list affected only one plug-in. | |||
[[File:IncludePy.png| 500px]] | |||
; External library: include + name of the chosen library | |||
<code lang="py">import sys | |||
ver = sys.version_info | |||
vs.Message(repr(ver)) | |||
</code> | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| '''Encryption''' | | '''Encryption''' | ||
| | See [[VS:Include_Files_and_Encryption| encryption]] for more infos. | ||
| | | | ||
; vss: - | |||
; px: encrypt upon launching the Encryption command (in the Plug-in Manager dialog, click on the button ''Edit Script...'' while pressing shift + caps lock + alt + cmd) | |||
{$INCLUDE ..\..\_VS_includes\_common\Utils.px} | |||
{$INCLUDE ..\..\_VS_includes\_common\Math.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). | |||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| ''' | | '''Linting''' | ||
| | | | ||
| <code>import vs</code> | |||
|- style="vertical-align: top;" | |||
| '''Python Version''' | |||
| - | |||
| <code>import sys | | <code>import sys | ||
ver = sys.version_info</br> | ver = sys.version_info</br> | ||
vs.Message(repr(ver))</br> | vs.Message(repr(ver))</br> | ||
</code> | </code> | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| '''Python Caching''' | |||
| '''Caching''' | |||
: some caching prevents your script to reflect changes: | : some caching prevents your script to reflect changes: | ||
| | | | ||
| varPersistentPythonEngine = 412 { Boolean } | | varPersistentPythonEngine = 412 { Boolean } | ||
In the SDK starting from VW 2014 we can read: | In the SDK starting from VW 2014 we can read: | ||
''When True the Python engine is the same for the execution of all scripts, this solves some issues with Py_Initialize and Py_Finalize. For example, when debugging externally python leaves threas that cause crash if Py_Initialize and Py_Finalize is used for each script call. So, this allows the engine to be preserved between calls, however Vectorworks will delete all custom modules and objects defined in the engine prior each execution.'' | ''When True the Python engine is the same for the execution of all scripts, this solves some issues with Py_Initialize and Py_Finalize. For example, when debugging externally python leaves threas that cause crash if Py_Initialize and Py_Finalize is used for each script call. So, this allows the engine to be preserved between calls, however Vectorworks will delete all custom modules and objects defined in the engine prior each execution.'' | ||
|} | |} | ||
Line 318: | Line 414: | ||
== Errors == | == Errors == | ||
Python Error Messages: | Python Error Messages: | ||
Revision as of 09:09, 21 January 2021
VS-Python Rosetta Stone
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.
Set up Python (Mac)
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:
python3 --version
- if there is an error, you should install Python 3 and configure it.
- 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 the 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, which is available at www.python.org/downloads/release/python-391/
After that I proceeded with the configurations as described in installpython3.com/mac/ and all seems well enough.
Set up an editor
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), click on the search field, enter ms-python, click on install Python.
VS - Py
Syntax Pitfalls
Description | Vectorscript Pascal | Vectorscript Python
|
---|---|---|
Indenting | irrelevant | Fatal:
you used both spaces and tabs to indent your code. This occurs frequently while copy-pasting across sources. Error Message: unindent does not match any outer indentation level you added an extra indent. This is common in Pascal, just to visually organise the code. Error Message: unexpected indent
|
Semicolon | Always needed:
|
Only needed for multiple statements on one line:
Error Message: SyntaxError: invalid syntax
|
Case sensitivity | Not case sensitive:
|
Case sensitive:
Error Message: AttributeError: 'module' object has no attribute 'vs.ALRTDIALOG'
|
Brakets
|
No brakets
|
Brakets
Error Message: - none! be careful! - |
FOR statements | Runs including last value:
{ runs 3 times! 1, 2 and 3 } FOR i := 1 TO 3 DO AlrtDialog(Concat(i)); |
Runs excluding last value:
# runs 2 times! 1 and 2 for i in range(1, 3): vs.AlrtDialog(str(i))
|
Concatenate text | Supports implicit conversion: | Doesn't support implicit conversion:
Error Message: TypeError: unsupported operand type(s) for +: 'int' and 'str' |
Variable Pitfalls
Description | Vectorscript Pascal | Vectorscript Python
|
---|---|---|
Setting VARs, returning Values | variable returned divided from VARs set
FUNCTION GetCustomObjectInfo( ok := GetCustomObjectInfo( objectName, objectHand, recordHand, wallHand ); |
variable returned and VARs set before routine
def vs.GetCustomObjectInfo(): return (BOOLEAN, objectName, objectHand, recordHand, wallHand) ok, objectName, objectHand, recordHand, wallHand = vs.GetCustomObjectInfo( )
|
Variable scope
|
Global wins over local:
{ GLOBAL ACCESS } { parent of subroutine "Increment" } PROCEDURE Main; VAR { good praxis: label globals with "g" } gIndex, gNum : INTEGER; { subroutine } PROCEDURE Increment; BEGIN { gNum is not defined in this subroutine the parser climbs up parent containers until it finds a declaration for the var gNum. In this case it can be found in Main } gNum := gNum +1; SysBeep; END; BEGIN gNum := 10; { init } FOR gIndex := 1 TO 10 DO Increment; { increments the variable gNum } AlrtDialog(Concat(gNum)); { returns 20 } END; Run(Main); |
Local wins over global:
# LOCAL ACCESS # subroutine def Increment(): # gNum is not defined in this subroutine # the parser creates a local instance of the var gNum! gNum +=1 vs.SysBeep gNum = 10 # init for gIndex in range(1, 10): Increment # increments the variable gNum # but only inside Increment! vs.AlrtDialog(str(gNum)) # returns 10! The global var didn't set # GLOBAL ACCESS: CORRECT # subroutine def Increment(): # gNum is not defined in this subroutine # tell the parser that you want to edit gNum global! global gNum gNum +=1 vs.SysBeep() gNum = 10 # init # please observe that the range is NOT 1, 10! for gIndex in range(0, 10): Increment() # increments globally the variable gNum vs.AlrtDialog(str(gNum)) # returns 20 # GLOBAL ACCESS: WRONG # subroutine def Increment(): # gNum is not defined in this subroutine # tell the parser that you want to edit gNum global! global gNum gNum +=1 vs.SysBeep() # no init! for gIndex in range(0, 10): Increment() # increments the variable gNum # but gNum is not inited with a starting value, so you get an error vs.AlrtDialog(str(gNum)) # rises error Error Message: NameError: global name 'gNum' is not defined
|
|
h <> NIL |
h != None h != vs.Handle() # not inited instance of a handle, how cryptic |
Fetching Plug-in Parameters | Direct:
MoveTo(PCONTROLPOINT01X, PCONTROLPOINT01Y); LineTo(PCONTROLPOINT02X, PCONTROLPOINT02Y); |
Prefixed with vs:
vs.MoveTo(vs.PControlPoint01X, vs.PControlPoint01Y) vs.LineTo(vs.PControlPoint02X, vs.PControlPoint02Y)
|
Colors |
|
Error Message: - none! be careful! - |
Includes / Imports
Description | Vectorscript Pascal | Vectorscript Python |
---|---|---|
Includes/Import
Load libraries of code |
$INCLUDE libraryFolder\libraryFile.vss $INCLUDE libraryFolder\libraryFile.px
|
import sys ver = sys.version_info vs.Message(repr(ver))
|
Encryption
See encryption for more infos. |
{$INCLUDE ..\..\_VS_includes\_common\Utils.px} {$INCLUDE ..\..\_VS_includes\_common\Math.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).
|
Linting | import vs
| |
Python Version | - | import sys
|
Python Caching
|
varPersistentPythonEngine = 412 { Boolean }
In the SDK starting from VW 2014 we can read: When True the Python engine is the same for the execution of all scripts, this solves some issues with Py_Initialize and Py_Finalize. For example, when debugging externally python leaves threas that cause crash if Py_Initialize and Py_Finalize is used for each script call. So, this allows the engine to be preserved between calls, however Vectorworks will delete all custom modules and objects defined in the engine prior each execution. |
Lists
Lists are powerful in Python, below some fascinating lists 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'}
Errors
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 +-- SystemError +-- TypeError +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning