[IronPython] Embedding IronPython and calling python functions from C#

Dino Viehland dinov at microsoft.com
Tue Jun 16 02:52:23 CEST 2009


You can set the variables in ScriptRuntime.Globals but then the user
will need to import them from Globals to have access to them.  There's no
way to automatically expose globals to every script though.

> -----Original Message-----
> From: users-bounces at lists.ironpython.com [mailto:users-
> bounces at lists.ironpython.com] On Behalf Of Patrick van der Willik
> Sent: Monday, June 15, 2009 5:38 PM
> To: Discussion of IronPython
> Subject: Re: [IronPython] Embedding IronPython and calling python
> functions from C#
>
> The OnConnect is in the autoexec.py yes. While this works perfectly for
> setting variables, how does this work when I want to set my callback
> functions? I have several helper functions which reside on the C# side
> of my application in objects which I cannot spawn from within my
> scripts(As they're of vital importance to actually start my
> application).
>
> I actually thought the scope I created was shared. Is there a way to
> get
> this working, so I can update the global table
>
> Is there a way so I can update the global scope?
>
> Michael Foord wrote:
> > Patrick van der Willik wrote:
> >> I am in fact using the 2nd 'flavour':
> >>                 string modInvoke = String.Format("import {0}\nfrom
> >> {0} import *\n", "autoexec");
> >
> > So OnConnect is defined in your autoexec.py module?
> >
> > In this case it is looking for x in the scope in which it is defined
> > *not* in the scope from which it is called (lexical scoping).
> >
> > You should make x another parameter - and perhaps in modInvoke create
> > a wrapper function that looks up x in its scope and passes it to
> > OnConnect.
> >
> > Michael
> >
> >>                                var source =
> >> engine.CreateScriptSourceFromString(modInvoke,
> >> SourceCodeKind.Statements);
> >>                 CompiledCode cc = source.Compile();
> >>                 cc.Execute(scope);
> >>
> >>                 // And bind our public delegates
> >>                 OnConnect = scope.GetVariable<Func<User,
> >> bool>>("OnConnect");
> >>                 OnDisconnect = scope.GetVariable<Func<User,
> >> bool>>("OnDisconnect");
> >>                 OnDataRecv = scope.GetVariable<Func<User, string,
> >> bool>>("OnDataReceived");
> >>                 OnPreLogin = scope.GetVariable<Func<User,
> >> bool>>("OnPreLogin");
> >>                 OnLogin = scope.GetVariable<Func<User,
> >> bool>>("OnLogin");
> >>
> >>                 Func<string> test = new Func<string>(Test);
> >>                 scope.SetVariable("x", 10);
> >>                 scope.SetVariable("Test", test);
> >>
> >> And in a later piece of code, I just call the OnConnect(newUser)
> >> delegate(in my C# part). Perhaps interesting to know, the autoexec
> >> has an import clientconn and from clientconn import *.
> >>
> >> Is my assumption that should work correct or am I missing something?
> >>
> >> Patrick
> >>
> >> Dino Viehland wrote:
> >>> What about the code which is actually running the code that "def
> >>> OnConnect" lives in?
> >>>
> >>> I would expect you have either:
> >>>         engine.ExecuteFile(..., scope)
> >>>
> >>> or:
> >>>
> >>>
> >>> code = engine.CreateScriptSource*(...)
> >>> cc = code.Compile()
> >>> cc.Execute(scope)
> >>>
> >>> or
> >>>
> >>> code = engine.CreateScriptSource*(...)
> >>> code.Execute(scope)
> >>>
> >>> where scope in all of these would be the scope that you've
> populated
> >>> with the value of "x".
> >>>
> >>> I suspect the 2nd one is the one you want so that you can run the
> >>> same code against multiple
> >>> scopes w/ different sets of bound variables based upon the current
> >>> request.
> >>>
> >>>
> >>> -----Original Message-----
> >>> From: users-bounces at lists.ironpython.com
> >>> [mailto:users-bounces at lists.ironpython.com] On Behalf Of Patrick
> van
> >>> der Willik
> >>> Sent: Monday, June 15, 2009 4:26 PM
> >>> To: Discussion of IronPython
> >>> Subject: Re: [IronPython] Embedding IronPython and calling python
> >>> functions from C#
> >>>
> >>> The actual code that uses these variables from within a script
> looks
> >>> like this:
> >>> def OnConnect(user):
> >>>     s = "The value of x: " + str(x)
> >>>     user.Send(s, True)
> >>>     user.Receiver = "user_username"
> >>>     return True
> >>>
> >>> And the complete exception is:
> >>> [ERROR] [16-6-2009 1:18:16] An error occured while attempting to
> accept
> >>> a new connection. Error: name 'x' is not defined
> >>> [ERROR] [16-6-2009 1:18:16] Stacktrace:    at
> >>> IronPython.Runtime.PythonContext.MissingName(SymbolId name)
> >>>    at
> Microsoft.Scripting.Runtime.ModuleGlobalWrapper.GetCachedValue()
> >>>    at
> >>> Microsoft.Scripting.Runtime.ModuleGlobalWrapper.get_CurrentValue()
> >>>    at S$2.OnConnect$6(Object user)
> >>>    at _stub_$17##8(Closure , CallSite , Object , User )
> >>>    at
> Microsoft.Scripting.Actions.MatchCaller.Call2[T0,T1,TRet](Func`4
> >>> target, CallSite site, Object[] args)
> >>>    at
> >>> Microsoft.Scripting.Actions.CallSite`1.UpdateAndExecute(Object[]
> args)
> >>>    at
> >>>
> Microsoft.Scripting.Actions.UpdateDelegates.Update2[T,T0,T1,TRet](CallS
> ite
> >>>
> >>> site, T0 arg0, T1 arg1)
> >>>    at System.Boolean(User)(Object[] , User )
> >>>    at TestProject.Users.ConnectionManager.AcceptNewConnnections()
> in
> >>> C:\Users\Patrick\Documents\Visual Studio
> >>> 2008\Projects\test\TestProject\Users\ConnectionManager.cs
> >>> :line 108
> >>>
> >>> Weird thing is: If I use GetVariable, it works fine. The call is
> >>> done at
> >>> a later location in the program that where I do the SetVariable,
> but
> >>> the
> >>> script scope hasn't ben changed in the meantime.
> >>>
> >>> Patrick
> >>>
> >>> Michael Foord wrote:
> >>>
> >>>> Patrick van der Willik wrote:
> >>>>
> >>>>> Alright, that actually really worked pretty good, and I finally
> got
> >>>>> it all working as it should. However, I'm running into 1 more
> little
> >>>>> issue, now I need to go the other way around aswell. I have
> several
> >>>>> functions marked in my application as PythonExportable. In a
> certain
> >>>>> startup phase of the application, after creating the IronPython
> >>>>> hosting environment, I walk over all these classes using
> Reflection,
> >>>>> take the tagged functions and put these into my IP scope.
> >>>>>
> >>>>> However, my simple tests for some reason cause my SetVariable()
> calls
> >>>>> to not work. I added 2 tests to my scripts, one where I add a
> >>>>> variable into the scope and another one where I add a delegate.
> >>>>> However, in both cases, whenever I use these variables from
> within my
> >>>>> scripts, they don't seem to work. Code:
> >>>>>                Func<string> test = new Func<string>(Test);
> >>>>>                scope.SetVariable("x", 10);
> >>>>>                scope.SetVariable("Test", test);
> >>>>>
> >>>>> Accessing them in my scripts have the effect of triggering an
> >>>>> exception that shows that x is undefined.
> >>>>>
> >>>> Can you show the actual code that attempts to use them and the
> actual
> >>>> exception message raised.
> >>>>
> >>>> Michael
> >>>>
> >>>>
> >>>>> Some insights into this would be of great help.
> >>>>>
> >>>>> Patrick
> >>>>>
> >>>>> Michael Foord wrote:
> >>>>>
> >>>>>> See this section of my hosting article:
> >>>>>>
> >>>>>>
> http://www.voidspace.org.uk/ironpython/hosting_api.shtml#functions-as-
> delegates
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> You cast the function to a delegate as you fetch it out of the
> >>>>>> scope.
> >>>>>>
> >>>>>> Michael
> >>>>>>
> >>>>>> Patrick van der Willik wrote:
> >>>>>>
> >>>>>>> I'm a bit late with responding to this as I was kinda busy. I
> used
> >>>>>>> the code that was given Stephen and it seems to run properly
> >>>>>>> without throwing exceptions. However, I created a little
> >>>>>>> autoexec.py file with a simple function in it with 2 parameters.
> >>>>>>>
> >>>>>>> The main problem here is: How do I call the function through
> the
> >>>>>>> scope? I used engine.CreateScope() to create myself a new scope,
> >>>>>>> but from there on, I'm basically lost(again). What I basically
> want
> >>>>>>> to do, is call my function 'add' with 2 parameters(say, 10 and
> 15).
> >>>>>>> The modules itself are loaded into a ScriptSource.
> >>>>>>>
> >>>>>>> Thanks,
> >>>>>>> Patrick
> >>>>>>>
> >>>>>>> Lepisto, Stephen P wrote:
> >>>>>>>
> >>>>>>>> What I do when I want to work with python modules from
> embedded
> >>>>>>>> IronPython is set the IronPython search path with the path of
> the
> >>>>>>>> module to load then  create and execute a small python script
> that
> >>>>>>>> loads the main python modules into the current scope.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> string moduleName = Path.GetFileName(modulePath);
> >>>>>>>>
> >>>>>>>> string path = Path.GetDirectoryName(modulePath);
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> ICollection<string> paths = _pythonEngine.GetSearchPaths();
> >>>>>>>>
> >>>>>>>> if (!paths.Contains(path))
> >>>>>>>>
> >>>>>>>> {
> >>>>>>>>
> >>>>>>>>     paths.Add(path);
> >>>>>>>>
> >>>>>>>>     _pythonEngine.SetSearchPaths(paths);
> >>>>>>>>
> >>>>>>>> }
> >>>>>>>>
> >>>>>>>> string modInvoke = String.Format("import {0}\nfrom {0} import
> >>>>>>>> *\n", moduleName);
> >>>>>>>>
> >>>>>>>> ScriptSource source =
> >>>>>>>> _pythonEngine.CreateScriptSourceFromString(modInvoke,
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> Microsoft.Scripting.SourceCodeKind.Statements);
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> Where modulePath is the full path to the python module or
> package
> >>>>>>>> to load.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> I can then invoke methods or access attributes using the
> >>>>>>>> IronPython scope.  In this way, I can interact with the python
> >>>>>>>> modules for as long as necessary before closing down the
> >>>>>>>> scope/engine.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> *From:* users-bounces at lists.ironpython.com
> >>>>>>>> [mailto:users-bounces at lists.ironpython.com] *On Behalf Of
> *Dody
> >>>>>>>> Gunawinata
> >>>>>>>> *Sent:* Thursday, June 11, 2009 9:09 AM
> >>>>>>>> *To:* Discussion of IronPython
> >>>>>>>> *Subject:* Re: [IronPython] Embedding IronPython and calling
> >>>>>>>> python functions from C#
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> You can read all yours file scripts, then using StringBuilder
> to
> >>>>>>>> combine then and call CreateScriptSourceFromString()
> >>>>>>>>
> >>>>>>>> Then you can call your functions within the combined scripts
> >>>>>>>> normally. Pretty much you are creating a giant source code on
> the
> >>>>>>>> fly.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> On Thu, Jun 11, 2009 at 5:32 PM, Patrick van der Willik
> >>>>>>>> <patrick at toolmaker.nl <mailto:patrick at toolmaker.nl>> wrote:
> >>>>>>>>
> >>>>>>>> I'm currently attempting to embed the IronPython 2 runtimes
> into
> >>>>>>>> an existing application written in C#. However, I find the
> amount
> >>>>>>>> of documentation lacking on what I'm trying to do. I currently
> >>>>>>>> have a proof-of-concept version which uses Lua and
> LuaInterface,
> >>>>>>>> but the people who have to write the scripts dislike Lua(Well,
> >>>>>>>> more hate it with a passion) and would love to see this
> working
> >>>>>>>> with Python.
> >>>>>>>>
> >>>>>>>> My host application is a networked application that must
> trigger
> >>>>>>>> certain scripts functions on events generated by the connected
> >>>>>>>> clients. The idea is that when my application starts, it will
> load
> >>>>>>>> the IronPython script environment, launches an 'autoexec.py'
> which
> >>>>>>>> will load various other scripts files and do some housekeeping.
> >>>>>>>> Once this all is completed, it will start listening to
> incoming
> >>>>>>>> connections. However, in various scenarios, the application
> has to
> >>>>>>>> trigger scripted functions when data is received from a client.
> >>>>>>>> Which script function is called is different per client and
> per
> >>>>>>>> event. I have events for connecting, logging on, disconnecting
> and
> >>>>>>>> a set of data specific events after receiving data. This
> highly
> >>>>>>>> depends on the received packets.
> >>>>>>>>
> >>>>>>>> My question here is: How do I embed IronPython in such a
> fashion
> >>>>>>>> that I can load my scripts and then trigger various functions
> >>>>>>>> within that? I've seen many examples that just call
> >>>>>>>> CreateScriptSourceFromString() or File each time in which just
> 1
> >>>>>>>> piece of code is implemented. This is not suitable for the
> needs
> >>>>>>>> here because the scripted systems can become quite complex.
> >>>>>>>>
> >>>>>>>> With regards,
> >>>>>>>> Patrick
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> _______________________________________________
> >>>>>>>> Users mailing list
> >>>>>>>> Users at lists.ironpython.com <mailto:Users at lists.ironpython.com>
> >>>>>>>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> --
> >>>>>>>> nomadlife.org <http://nomadlife.org>
> >>>>>>>>
> >>>>>>>> --------------------------------------------------------------
> ----------
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> _______________________________________________
> >>>>>>>> Users mailing list
> >>>>>>>> Users at lists.ironpython.com
> >>>>>>>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >>>>>>>>
> >>>>>>>>
> >>>>>>> ---------------------------------------------------------------
> ---------
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> _______________________________________________
> >>>>>>> Users mailing list
> >>>>>>> Users at lists.ironpython.com
> >>>>>>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>> _______________________________________________
> >>>>> Users mailing list
> >>>>> Users at lists.ironpython.com
> >>>>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >>>>>
> >>>>
> >>>
> >>> _______________________________________________
> >>> Users mailing list
> >>> Users at lists.ironpython.com
> >>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >>> _______________________________________________
> >>> Users mailing list
> >>> Users at lists.ironpython.com
> >>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >>>
> >>>
> >>
> >> --------------------------------------------------------------------
> ----
> >>
> >> _______________________________________________
> >> Users mailing list
> >> Users at lists.ironpython.com
> >> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >>
> >
> >
>
> _______________________________________________
> Users mailing list
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com




More information about the Ironpython-users mailing list