Difference between revisions of "Developing Python Modules with Pascal"
(First draft) |
(Added subtopics) |
||
Line 6: | Line 6: | ||
You can extend Python by developing compiled libraries (called modules) that add functions to Python. This topic discusses how to create a library with Pascal (Delphi or Free Pascal). | You can extend Python by developing compiled libraries (called modules) that add functions to Python. This topic discusses how to create a library with Pascal (Delphi or Free Pascal). | ||
+ | |||
+ | == Minimum Python API == | ||
Copy and paste this code into a text editor and save it as file PyAPI.pas: | Copy and paste this code into a text editor and save it as file PyAPI.pas: | ||
Line 31: | Line 33: | ||
const | const | ||
{$IFDEF MSWINDOWS} | {$IFDEF MSWINDOWS} | ||
+ | {$IFDEF USE_PYTHON23} | ||
+ | PythonLib = 'python23.dll'; | ||
+ | {$ELSE} | ||
PythonLib = 'python25.dll'; | PythonLib = 'python25.dll'; | ||
+ | {$ENDIF} | ||
{$ENDIF} | {$ENDIF} | ||
+ | |||
{$IFDEF LINUX} | {$IFDEF LINUX} | ||
+ | {$IFDEF USE_PYTHON23} | ||
+ | PythonLib = 'python23.so'; | ||
+ | {$ELSE} | ||
PythonLib = 'python25.so'; | PythonLib = 'python25.so'; | ||
+ | {$ENDIF} | ||
{$ENDIF} | {$ENDIF} | ||
+ | |||
{$IFDEF DARWIN} | {$IFDEF DARWIN} | ||
− | PythonLib = ''; //Link against Python.framework (-k-framework -kPython) | + | PythonLib = ''; //Link against Python.framework (-k-framework -kPython). |
+ | // To link Python 2.3, add -k-F/System/Library/Frameworks | ||
{$ENDIF} | {$ENDIF} | ||
Line 51: | Line 64: | ||
const | const | ||
+ | {$IFDEF USE_PYTHON23} | ||
+ | PYTHON_API_VERSION = 1012; //Also used with Python 2.4 | ||
+ | {$ELSE} | ||
PYTHON_API_VERSION = 1013; | PYTHON_API_VERSION = 1013; | ||
+ | {$ENDIF} | ||
METH_VARARGS = 1; | METH_VARARGS = 1; | ||
Line 73: | Line 90: | ||
</pre> | </pre> | ||
− | If you have a different version of Python, just change the library name (PythonLib). If you need other Python API functions, just add them to PyAPI.pas following the example of PyInt_FromLong. | + | If you have a different version of Python, define USE_PYTHON23 to link against version 2.3 or just change the library name (PythonLib). If you need other Python API functions, just add them to PyAPI.pas following the example of PyInt_FromLong. |
+ | |||
+ | == A simple module example == | ||
Here is a simple library that uses this Python API unit. Copy and paste this code into a text editor and save it as file PyMinMod.dpr: | Here is a simple library that uses this Python API unit. Copy and paste this code into a text editor and save it as file PyMinMod.dpr: |
Revision as of 21:05, 2 January 2009
Template:Developing Python Modules with Pascal
Introduction
Python is a popular scripting language that is often used to add functionality to other applications such as OpenOffice and Quantum GIS. Your computer may already have a version of Python installed. If not, you can download Python from the official Website: http://www.python.org/.
You can extend Python by developing compiled libraries (called modules) that add functions to Python. This topic discusses how to create a library with Pascal (Delphi or Free Pascal).
Minimum Python API
Copy and paste this code into a text editor and save it as file PyAPI.pas:
unit PyAPI; { Minimum set of Python function declarations for module libraries. Author: Phil (MacPgmr at fastermac.net). To add other Python function declarations, see the Python header files (.h) included with every Python distribution. } {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface const {$IFDEF MSWINDOWS} {$IFDEF USE_PYTHON23} PythonLib = 'python23.dll'; {$ELSE} PythonLib = 'python25.dll'; {$ENDIF} {$ENDIF} {$IFDEF LINUX} {$IFDEF USE_PYTHON23} PythonLib = 'python23.so'; {$ELSE} PythonLib = 'python25.so'; {$ENDIF} {$ENDIF} {$IFDEF DARWIN} PythonLib = ''; //Link against Python.framework (-k-framework -kPython). // To link Python 2.3, add -k-F/System/Library/Frameworks {$ENDIF} type PyMethodDef = packed record name : PChar; //Python function name meth : Pointer; //Address of function that implements it flags : Integer; //METH_xxx flags; describe function's arguments doc : PChar; //Description of funtion end; PyObject = Pointer; const {$IFDEF USE_PYTHON23} PYTHON_API_VERSION = 1012; //Also used with Python 2.4 {$ELSE} PYTHON_API_VERSION = 1013; {$ENDIF} METH_VARARGS = 1; function Py_InitModule( name : PChar; var methods : PyMethodDef; doc : PChar = nil; self : PyObject = nil; apiver : LongInt = PYTHON_API_VERSION) : PyObject; cdecl; external PythonLib name 'Py_InitModule4'; function PyArg_ParseTuple(args : PyObject; format : PChar) : Integer; cdecl; varargs; external PythonLib; //Note varargs allows us to simulate C variable number of arguments (...). function PyInt_FromLong(along : LongInt) : PyObject; cdecl; external PythonLib; implementation end.
If you have a different version of Python, define USE_PYTHON23 to link against version 2.3 or just change the library name (PythonLib). If you need other Python API functions, just add them to PyAPI.pas following the example of PyInt_FromLong.
A simple module example
Here is a simple library that uses this Python API unit. Copy and paste this code into a text editor and save it as file PyMinMod.dpr:
library PyMinMod; { Minimal Python module (library) that includes a single function. Author: Phil (MacPgmr at fastermac.net). For a good explanation of modules from a C perspective, see: http://superjared.com/entry/anatomy-python-c-module/ To compile this module: - With Delphi: Open this .dpr file and compile. - With Lazarus: Open .lpi file and compile. To deploy module: - With Delphi: Rename compiled .dll to .pyd. - With Lazarus on Windows: Rename compiled .so to .pyd. - With Lazarus on OS X and Linux: .so extension is okay. } uses SysUtils, PyAPI; function SumTwoIntegers(Self : PyObject; Args : PyObject) : PyObject; cdecl; var Arg1 : Integer; Arg2 : Integer; begin PyArg_ParseTuple(Args, 'ii', @Arg1, @Arg2); //Get the two input arguments Result := PyInt_FromLong(Arg1 + Arg2); //Add them together and return sum end; var Methods : packed array [0..1] of PyMethodDef; procedure initPyMinMod; cdecl; begin Methods[0].name := 'SumTwoIntegers'; Methods[0].meth := @SumTwoIntegers; Methods[0].flags := METH_VARARGS; Methods[0].doc := 'Tests argument passing to and from module function'; Methods[1].name := nil; Methods[1].meth := nil; Methods[1].flags := 0; Methods[1].doc := nil; Py_InitModule('PyMinMod', Methods[0]); end; exports initPyMinMod; end.
You can add more functions to the module by following the example in initPyMinMod.
With Delphi, just open PyMinMod.dpr and compile; with Lazarus, you'll probably want to create a project file. You can do that yourself or just copy and paste this project file into a text editor and save it as file PyMinMod.lpi:
<?xml version="1.0"?> <CONFIG> <ProjectOptions> <PathDelim Value="/"/> <Version Value="6"/> <General> <MainUnit Value="0"/> <IconPath Value="./"/> <TargetFileExt Value=".exe"/> <UseAppBundle Value="False"/> <ActiveEditorIndexAtStart Value="0"/> </General> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <Units Count="1"> <Unit0> <Filename Value="PyMinMod.dpr"/> <IsPartOfProject Value="True"/> <UnitName Value="PyMinMod"/> <CursorPos X="1" Y="1"/> <TopLine Value="1"/> <EditorIndex Value="0"/> <UsageCount Value="20"/> <Loaded Value="True"/> <SyntaxHighlighter Value="Delphi"/> </Unit0> </Units> <JumpHistory Count="0" HistoryIndex="-1"/> </ProjectOptions> <CompilerOptions> <Version Value="8"/> <Target> <Filename Value="PyMinMod.so"/> </Target> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <CStyleOperator Value="False"/> <AllowLabel Value="False"/> <CPPInline Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Options> <PassLinkerOptions Value="True"/> <LinkerOptions Value="-framework Python"/> <Win32> <GraphicApplication Value="True"/> </Win32> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <CompilerPath Value="$(CompPath)"/> </Other> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="ECodetoolError"/> </Item1> <Item2> <Name Value="EFOpenError"/> </Item2> </Exceptions> </Debugging> </CONFIG>
Once you've compiled the module, rename it if necessary per the comments in PyMinMod.dpr. Then test the module by creating a simple test.py file that contains these two lines:
import PyMinMod print "Value returned by SumTwoIntegers: " + str(PyMinMod.SumTwoIntegers(1, 2))
Note that Python is case sensitive so if your compiled module is in lower-case, change the "PyMinMod" references accordingly.
Now open a terminal window and run the script like this:
python test.py
The script should output the following line:
Value returned by SumTwoIntegers: 3
What we've done here is create a simple Python module that implements a Python function for adding two integers. Once you've imported the module into your Python script, you can use the function in the same way that you use built-in Python functions.