User:CBM-c-/VS-Py Rosetta Stone: Difference between revisions
(→Variables: expand) |
(→Variables: consolidate about vars) |
||
Line 140: | Line 140: | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| ''' | | '''Returning Values''' | ||
| ''' | | '''Results left, VARs and arguments right''' | ||
<code lang="pas"> | <code lang="pas"> | ||
FUNCTION ActiveClass : STRING; | |||
classN := ActiveClass; | |||
</code> | |||
<code lang="pas"> | |||
FUNCTION GetCustomObjectInfo( | |||
VAR objectName :STRING; | |||
VAR objectHand :HANDLE; | |||
VAR recordHand :HANDLE; | |||
VAR wallHand :HANDLE) : BOOLEAN; | |||
ok := GetCustomObjectInfo( objectName, objectHand, recordHand, wallHand ); | |||
</code> | |||
<code lang="pas"> | |||
PROCEDURE HMove( | |||
objectHand :HANDLE; | |||
xOffset :REAL; | |||
yOffset :REAL); | |||
HMove( objectHand, xOffset, yOffset ); | |||
</code> | |||
| '''Results left, VARs left, arguments right''' | |||
<code lang="py"> | |||
def vs.ActiveClass(): | |||
return STRING | |||
classN = vs.ActiveClass() | |||
</code> | </code> | ||
< | <code lang="py"> | ||
def vs.GetCustomObjectInfo(): | |||
return (BOOLEAN, objectName, objectHand, recordHand, wallHand) | return (BOOLEAN, objectName, objectHand, recordHand, wallHand) | ||
</ | |||
ok, objectName, objectHand, recordHand, wallHand = vs.GetCustomObjectInfo( ) | |||
</code> | |||
<code lang="py"> | <code lang="py"> | ||
def vs.HMove(objectHand, xOffset, yOffset): | |||
return None | |||
vs.HMove(objectHand, xOffset, yOffset) | |||
</code> | </code> | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
Line 179: | Line 211: | ||
|- style="vertical-align: top;" | |- style="vertical-align: top;" | ||
| '''Variable scope''' | | '''Variable scope''' | ||
: perhaps the largest source of error | : perhaps the largest source of error while transitioning to python | ||
| | | | ||
'''Global wins over local:''' | '''Global wins over local:''' |
Revision as of 08:02, 25 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
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' |
Variables
Description | Vectorscript Pascal | Vectorscript Python
|
---|---|---|
Returning Values | Results left, VARs and arguments right
FUNCTION ActiveClass : STRING; classN := ActiveClass; 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 right
def vs.ActiveClass(): return STRING classN = 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 vs.HMove(objectHand, xOffset, yOffset) |
Variable Attributes
discovered by P. Winkler 2017 |
none | built in in VW
h = 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:
{ GLOBAL ACCESS } { parent of subroutine "Increment" } PROCEDURE Main; VAR { good praxis: label globals with "g" } gIndex, gNum : INTEGER; { gNum is valid starting from here, downwards } { 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 vs.AlrtDialog(str(gNum)) # returns 10! The global var didn't set # GLOBAL ACCESS: CORRECT # subroutine def Increment(): global gNum # <----- gNum +=1 vs.SysBeep() gNum = 10 # init for gIndex in range(0, 10): Increment() vs.AlrtDialog(str(gNum)) # returns 20 # TRY GLOBAL ACCESS: WRONG def 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: WRONG global gNum # <----- wrong place! def Increment(): gNum +=1 vs.SysBeep() gNum = 10 for gIndex in range(0, 10): Increment() vs.AlrtDialog(str(gNum)) Error Message: UnboundLocalError: local variable 'gNum' referenced before assignment
|
|
h <> NIL |
h is None h is not None
h != None h != vs.Handle() # not inited instance of a handle, how cryptic See: www.python.org/dev/peps/pep-0008/#programming-recommendations |
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
In the example in screenshot the file z_Ramp.px is located 2 folders higher (..\..\) of the file .CBM-Ramp.vso, and within the folders \_VS\CBM-Ramp. There are compelling reasons to split the running code from the plug-ins. For example because you will want a plug-in for every VW major version, but not necessarily more code files.
|
Python calls Includes "imports". It searches for imports in the current directory, then in dedicated directories, if any (Script Options). For current directory Python understands the folder of the running .vso/.vsm/.vst file.
import main # import the script main.py, in the same folder as the running .vso/.vsm/.vst plug-in
import vs import math from subprocess import Popen, PIPE
import vs, math # not recommended
import mypkg.sibling from mypkg import sibling from mypkg.sibling import example
from . import sibling from .sibling import example See more in: www.python.org/dev/peps/pep-0008/#imports
import sys ver = sys.version_info vs.Message(repr(ver))
import vs Intellisense from Visual Studio Code:
|
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).
|
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