Page 1 of 2

Embedding Python into your apps

Posted: Mon Sep 27, 2010 9:32 pm
by epidemicz
There's a few things I have been wanting to work on lately and it seems like the easiest way to do them is to use python. But, I'm not satisfied with just using python, I wanna use PB too :D. I haven't seen much talk here about embedding python into a PB app, so I thought I'd give it a shot. I spent a little time researching and here's a quick example that I came up with.

**edit - I'm reposting to use infratec's example from below because mine was awful, awful and he was kind enough to correct me **

*Requires Python 3.1 (Change library name for other versions) - Get it here: http://python.org/download/ *

Code: Select all

Prototype Py_Initialize()
Prototype.s PyRun_SimpleString(String.s)
Prototype Py_Finalize()

If OpenConsole()

  If OpenLibrary(0, "python31.dll")
    PythonInitialize.Py_Initialize = GetFunction(0, "Py_Initialize")
    PythonRunSimpleString.PyRun_SimpleString = GetFunction(0, "PyRun_SimpleString")
    PythonFinalize.Py_Finalize = GetFunction(0, "Py_Finalize")
    
    PythonInitialize()
    
    pystring$ = "from time import time, ctime" + Chr(10)
    pystring$ + "print('Hello PB World from Python!')" + Chr(10)
    pystring$ + "print('Today is', ctime(time()))"
    
    PythonRunSimpleString(pystring$)
    
    PythonFinalize()
    
    CloseLibrary(0)
    
    Delay(3000)
  EndIf
  
  CloseConsole()

EndIf


Re: Embedding Python into your apps

Posted: Tue Sep 28, 2010 7:39 am
by infratec
Hi,

thank you for your code :D
Since my daughter has to learn python in school, I also started to learn it (a bit).

But I think It is not 100% clear for you how to use the prototypes in PB.

So I modified your code for python 3.1 and changed the prototype stuff

[Edit] removed my stuff, not longer neccessary :mrgreen: [/Edit]

Best regards,

Bernd

Re: Embedding Python into your apps

Posted: Tue Sep 28, 2010 8:24 am
by epidemicz
infratec wrote:Hi,

thank you for your code :D
Since my daughter has to learn python in school, I also started to learn it (a bit).

But I think It is not 100% clear for you how to use the prototypes in PB.

So I modified your code for python 3.1 and changed the prototype stuff

Best regards,

Bernd
Wow, you caught me haha. First time using prototypes, I believe, no wonder I was complaining to myself about how strange they seemed.

Really glad you showed me that, thanks!

Going to change the original post to use your code, because wow, I really goofed up. Thanks again infratec :D.

I suppose it would be useful if I prototyped out the whole dll, I'll try to do that sometime soon.

Re: Embedding Python into your apps

Posted: Tue Sep 28, 2010 8:41 am
by Kiffi
@epidemicz: Nice! Thanks for sharing Image

Greetings ... Kiffi

Re: Embedding Python into your apps

Posted: Tue Sep 28, 2010 11:45 am
by Kwai chang caine
I have also try with the portable version
ftp://ftp.heanet.ie/pub/portablepython/ ... y3.0.1.exe

That's works too, but the PB code must be in the "App" folder 8)
http://www.portablepython.com/wiki/Port ... 1.1Py3.0.1

Very very good idea ..thanks for sharing 8)

Re: Embedding Python into your apps

Posted: Tue Sep 28, 2010 4:03 pm
by rsts
Looks very cool. Gonna have to give it a try. Been wanting to do some python for quite a while now but hated leaving PB. This will provide the extra incentive.

Thanks for sharing.

cheers

Re: Embedding Python into your apps

Posted: Tue Sep 28, 2010 4:07 pm
by flaith
Purebasic with Python, cool, thanks epidemicz :D

Re: Embedding Python into your apps

Posted: Tue Sep 28, 2010 9:57 pm
by infratec
Hi,

hm, it was not very usefull to show stuff on the console.
So I played a bit and found the solution

Code: Select all

Prototype Py_Initialize()
Prototype.i PyRun_SimpleString(String.s)
Prototype.l PyImport_AddModule(String.s)
Prototype.l PyModule_GetDict(*Address)
Prototype.l PyDict_GetItemString(*Address, String.s)
Prototype.l PyLong_AsLong(*Address)
Prototype Py_Finalize()


If OpenLibrary(0, "python31.dll")
  Python_Initialize.Py_Initialize = GetFunction(0, "Py_Initialize")
  PythonRun_SimpleString.PyRun_SimpleString = GetFunction(0, "PyRun_SimpleString")
  
  PythonImport_AddModule.PyImport_AddModule = GetFunction(0, "PyImport_AddModule")
  PythonModule_GetDict.PyModule_GetDict = GetFunction(0, "PyModule_GetDict")
  PythonLong_AsLong.PyLong_AsLong = GetFunction(0, "PyLong_AsLong")
  PythonDict_GetItemString.PyDict_GetItemString = GetFunction(0, "PyDict_GetItemString")
  
  Python_Finalize.Py_Finalize = GetFunction(0, "Py_Finalize")
  
  Python_Initialize()
    
  PythonRun_SimpleString("result = 5 ** 2")
  *module = PythonImport_AddModule("__main__")
  *dictionary = PythonModule_GetDict(*module)
  *result = PythonDict_GetItemString(*dictionary, "result")
  Result.l = PythonLong_AsLong(*result)
  Debug Result
    
  Python_Finalize()
    
  CloseLibrary(0)
EndIf
So you can get results also without a console. :mrgreen:

Best regards,

Bernd

Re: Embedding Python into your apps

Posted: Wed Sep 29, 2010 7:27 am
by infratec
But...

what you can do in python, what is not possible in PureBASIC :?:

Bernd

Re: Embedding Python into your apps

Posted: Wed Sep 29, 2010 8:26 am
by epidemicz
infratec wrote:But...

what you can do in python, what is not possible in PureBASIC :?:

Bernd
I think the question should be more so, how can python improve your applications.

-Quicker development time
-Easy syntax
-Cross platform
-Flexibility, it opens your app up to many more code options, libraries, etc.

Personally, my interest started when I looked into the Google Talk API. Google has released a java and python library to handle XMPP communications. So, by embedding python into my app, I can control the most minute detail of it with PB and with python I can get up and going very quickly.

I mean, its not without its downside. I'm always hesitant to bring in dependencies, but for me it's well worth it.

Re: Embedding Python into your apps

Posted: Wed Sep 29, 2010 1:48 pm
by infratec
Ok,

so here it is a bit more:
Save this file as Python31.pbi

Code: Select all

;
; Python 3.1 for PureBASIC
; 


PrototypeC Py_Initialize()
PrototypeC Py_Finalize()

PrototypeC Py_IncRef(*PyObject)
PrototypeC Py_DecRef(*PyObject)


PrototypeC.i PyCallable_Check(*PyObject)

PrototypeC.l PyDict_GetItemString(*PyObject, String.s)

PrototypeC PyErr_Print()
PrototypeC.l PyErr_Occurred()
PrototypeC PyErr_Clear()

PrototypeC.l PyImport_AddModule(String.s)
PrototypeC.l PyImport_Import(*PyObject)

PrototypeC.l PyLong_AsLong(*PyObject)
PrototypeC.l PyLong_FromLong(Value.l)

PrototypeC.l PyModule_GetDict(*PyObject)

PrototypeC.l PyObject_GetAttrString(*PyObject, String.s)
PrototypeC.l PyObject_CallObject(*PyObject1, *pyObject2)

PrototypeC.i PyRun_SimpleString(String.s)

PrototypeC.l PyTuple_New(Len.l)
PrototypeC.i PyTuple_SetItem(*PyObject1, Size.l, *PyObject2)

PrototypeC.l PyUnicode_FromString(String.s)




Global PythonLib.l


Structure _typeobject
    *ob_base
    *tp_name.s          ; For printing, in format "<module>.<name>"
    tp_basicsize.i
    tp_itemsize.i       ; For allocation

    ; Methods To implement standard operations

    *tp_dealloc
    *tp_print
    *tp_getattr
    *tp_setattr
    *tp_reserved     ; formerly known as tp_compare
    *tp_repr

    ; Method suites For standard classes

    *tp_as_number
    *tp_as_sequence
    *tp_as_mapping

    ; More standard operations (here For binary compatibility)

    *tp_hash
    *tp_call
    *tp_str
    *tp_getattro
    *tp_setattro

    ; Functions To access object As input/output buffer
    *tp_as_buffer

    ; Flags To Define presence of optional/expanded features
    tp_flags.l;

    *tp_doc      ; Documentation string

    ; Assigned meaning in release 2.0
    ; call function For all accessible objects
    *tp_traverse

    ; delete references To contained objects
    *tp_clear;

    ; Assigned meaning in release 2.1
    ; rich comparisons
    *tp_richcompare

    ; weak reference enabler
    tp_weaklistoffset.i

    ; Iterators
    *tp_iter
    *tp_iternext

    ; Attribute descriptor And subclassing stuff
    *tp_methods
    *tp_members
    *tp_getset
    *tp_base
    *tp_dict
    *tp_descr_get
    *tp_descr_set
    *tp_dictoffset
    *tp_init
    *tp_alloc
    *tp_new
    *tp_free      ; Low-level free-memory routine
    *tp_is_gc      ; For PyObject_IS_GC
    *tp_bases
    *tp_mro      ; method resolution order
    *tp_cache
    *tp_subclasses
    *tp_weaklist
    *tp_del

    ; Type attribute cache version tag. Added in version 2.6
    tp_version_tag.u

CompilerIf 1 = 0  ;COUNT_ALLOCS
    ; these must be last And never explicitly initialized
    tp_allocs.i
    tp_frees.i
    tp_maxalloc.i
    *tp_prev
    *tp_next
CompilerEndIf
EndStructure








Structure PythonObject
  *_ob_next
  *_ob_prev
  ob_refcnt.i
  *ob_type._typeobject
EndStructure


Macro Python_INCREF(op)
  op\ob_refcnt + 1
EndMacro

Macro Python_XINCREF(op)
  If op : Python_INCREF(op) : EndIf
EndMacro

Macro Python_DECREF(op)
  op\ob_refcnt - 1
  If op\ob_refcnt <> 0
    ; Don't know how to do it
  Else
    ; Don't know how to do it
  EndIf
EndMacro

Macro Python_XDECREF(op)
  If op : Python_DECREF(op) : EndIf
EndMacro

Macro Python_CLEAR()
  If op
    *_py_tmp = op
    op = #Null
    Py_DECREF(*_py_tmp)
  EndIf
EndMacro



Procedure.i PythonInit()
  
  PythonLib = OpenLibrary(#PB_Any, "python31.dll")
  If PythonLib
    Global Python_Initialize.Py_Initialize = GetFunction(PythonLib, "Py_Initialize")
    Global Python_Finalize.Py_Finalize = GetFunction(PythonLib, "Py_Finalize")
    
    Global Python_IncRef.Py_IncRef = GetFunction(PythonLib, "Py_IncRef")
    Global Python_DecRef.Py_DecRef = GetFunction(PythonLib, "Py_DecRef")
    
    Global PythonCallable_Check.PyCallable_Check = GetFunction(PythonLib, "PyCallable_Check")
    
    Global PythonDict_GetItemString.PyDict_GetItemString = GetFunction(PythonLib, "PyDict_GetItemString")
    
    Global PythonErr_Print.PyErr_Print = GetFunction(PythonLib, "PyErr_Print")
    Global PythonErr_Occurred.PyErr_Occurred = GetFunction(PythonLib, "PyErr_Occurred")
    Global PythonErr_Clear.PyErr_Clear = GetFunction(PythonLib, "PyErr_Clear")
    
    Global PythonImport_AddModule.PyImport_AddModule = GetFunction(PythonLib, "PyImport_AddModule")
    Global PythonImport_Import.PyImport_Import = GetFunction(PythonLib, "PyImport_Import")
    
    Global PythonLong_AsLong.PyLong_AsLong = GetFunction(PythonLib, "PyLong_AsLong")
    Global PythonLong_FromLong.PyLong_FromLong = GetFunction(PythonLib, "PyLong_FromLong")
    
    Global PythonModule_GetDict.PyModule_GetDict = GetFunction(PythonLib, "PyModule_GetDict")
    
    Global PythonObject_GetAttrString.PyObject_GetAttrString = GetFunction(PythonLib, "PyObject_GetAttrString")
    Global PythonObject_CallObject.PyObject_CallObject = GetFunction(PythonLib, "PyObject_CallObject")
    
    Global PythonRun_SimpleString.PyRun_SimpleString = GetFunction(PythonLib, "PyRun_SimpleString")
    
    Global PythonTuple_New.PyTuple_New = GetFunction(PythonLib, "PyTuple_New")
    Global PythonTuple_SetItem.PyTuple_SetItem = GetFunction(PythonLib, "PyTuple_SetItem")
    
    Global PythonUnicode_FromString.PyUnicode_FromString = GetFunction(PythonLib, "PyUnicode_InternFromString")
  EndIf
  
  ProcedureReturn PythonLib
  
EndProcedure


Procedure PythonClose()
  
  If PythonLib
    CloseLibrary(PythonLib)
  EndIf
  
EndProcedure
Save this file as callpy.pb

Code: Select all

IncludeFile "Python31.pbi"




If OpenConsole()

  If CountProgramParameters() < 2
    PrintN("Usage: call pythonfile funcname [args]")    
    End 1
  EndIf
  
  If PythonInit()
    Python_Initialize()
    
    Debug ProgramParameter(0)
    
    *pName.PythonObject = PythonUnicode_FromString(ProgramParameter(0))
    ; Error checking of pName left out

    *pModule.PythonObject = PythonImport_Import(*pName)
    Python_DECREF(*pName)
    
    Debug ProgramParameter(1)
    
    If *pModule
      *pFunc.PythonObject = PythonObject_GetAttrString(*pModule, ProgramParameter(1))
      ; pFunc is a new reference
      If *pFunc And PythonCallable_Check(*pFunc)
        *pArgs.PythonObject = PythonTuple_New(CountProgramParameters() - 2)
        
        For i = 0 To CountProgramParameters() - 3
          *pValue.PythonObject = PythonLong_FromLong(Val(ProgramParameter(i + 2)))
          If Not *pValue
            Python_DECREF(*pArgs)
            Python_DECREF(*pModule);
            PrintN("Cannot convert argument")
            End 1
          EndIf
          ; pValue reference stolen here:
          PythonTuple_SetItem(*pArgs, i, *pValue)
        Next i
        
        *pValue.PythonObject = PythonObject_CallObject(*pFunc, *pArgs)
        Python_DECREF(*pArgs)
        If *pValue <> #Null
          PrintN("Result of call: " +  Str(PythonLong_AsLong(*pValue)))
          Python_DECREF(*pValue)
        Else
          Python_DECREF(*pFunc)
          Python_DECREF(*pModule)
          PythonErr_Print()
          PrintN("Call failed")
          End 1
        EndIf
        
      Else
        If PythonErr_Occurred()
          PythonErr_Print()
          PrintN("Cannot find function " + ProgramParameter(1))
        EndIf
      EndIf
      
    Else
      PythonErr_Print()
      PrintN("Failed to load " + ProgramParameter(0))
      End 1
    EndIf
       
    Python_Finalize()
  EndIf
  
  CloseConsole()
EndIf
And this as first.py

Code: Select all

def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c

#print(multiply1(4,2))
Than you should be able to do
callpy first multiply 2 3
at the console.

This is the example from the python tutorial converted to PureBASIC.

But unfortunately I miss something in the pbi file.
If someone has a solution, tell it.
(Look at the macro Python_DECREF)

Bernd

Re: Embedding Python into your apps

Posted: Thu Jan 28, 2016 11:37 am
by Kwai chang caine
I try to use this code but unfortunately without success :cry:
The worst it's before i try it, but now i not find the "python31.dll" and with the "python30.dll" i have an error at the line "Python_Initialize()" in the "Microsoft Visual C++ Runtime Library" with this text "This application has requested the Runtime to terminate it in an unusual way.Please contact the application's support team for more information."
I have try with pb v4.30, v4.51, 5.23 and nothing better :|
I use now W7, it's perhaps this the problem :?:

Someone have the correct PYTHON for use this code, or better the code for use one of the last PYTHON, for exampler 3.4 because i have the DLL

Re: Embedding Python into your apps

Posted: Thu Jan 28, 2016 2:24 pm
by infratec
Hi KCC,

less time, so ...

You can download Python 3.1.4
https://www.python.org/ftp/python/3.1.4 ... -3.1.4.msi
https://www.python.org/ftp/python/3.1.4 ... .amd64.msi

Install it,
copy the python31.dll from \windows\system32\ to a save place,
uninstall it

With this dll the example works. (just tested) Win7 x64 PB 5.41 x86 and python 3.1.4 x86

Bernd

Re: Embedding Python into your apps

Posted: Fri Jan 29, 2016 12:23 pm
by Kwai chang caine
Thanks a lot my friend, i do that
Have a good day 8)

Re: Embedding Python into your apps

Posted: Fri Jan 29, 2016 12:29 pm
by Dude
infratec wrote:what you can do in python, what is not possible in PureBASIC :?:
It constantly amazes me that people buy PureBasic but then still want to mix Python, machine code, OOP, and all other non-Basic stuff to it. Doesn't anyone buy it just for Basic anymore? :lol: