ok, so if you know me well, this gets a little complex...

what I'm trying to do is execute a function from a script that requires 2 arguments where the names varry depending on the script.
but I'd like that function to be executed in a namespace where I can limit it's execution to not use certain functions from my interface.

so here's something I've tried to simulate what I want to do:

>>> def f(a3,a1,a2): print a1,a2,a3
>>> f.__defaults__ = (3,1,2)
>>> f()
1 2 3
>>> exec f.__code__ in {} # limit execution to namespace

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    exec f.__code__ in {}
TypeError: f() takes exactly 3 arguments (0 given)

how can I get this working??

I've placed a3 first to test a dictionary behavior thing with a locals test which didn't work...
the name doesn't matter though as it's not limited to those names

nope:

>>> def f2(): print 'test failed'

>>> def f(a1,a2): f2() #should return a NameError

>>> f.__defaults__ = (1,2)
>>> exec 'f()' in {'f':f}
test failed
>>> 

I'm trying to localize the namespace, and the function f represents relatively the entire script
(the functions represented by f are basically import and export for models, animations, images, compression, etc. (whatever else I add support for))

exec 'f()' in {'f':f, 'f2':f2}

^this should be giving the result you're seeing above

Edited 1 Year Ago by Tcll

Here is something

>>> def f2(): print 'test failed'
... 
>>> def f(a1,a2): f2()
... 
>>> function = type(f)
>>> fclone = function(f.__code__, {}) # function with empty func_globals
>>> fclone.__defaults__ = (1,2)
>>> 
>>> exec 'f()' in {'f':fclone}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "<stdin>", line 1, in f
NameError: global name 'f2' is not defined

Edit: function() accepts a few other arguments. See the code of func_new() in python's C source code.

Edited 1 Year Ago by Gribouillis

that could work >.>

defined in FORMAT:

>>> def f2(): print 'test failed'
... 

defined by noobs in a script:

>>> def f(a1,a2): f2()
... 

defined in VIEWER and FORMAT in the I/O functions:

>>> function = type(f)
>>> fclone = function(f.__code__, {}) # function with empty func_globals
>>> fclone.__defaults__ = (1,2)
>>> 
>>> exec 'f()' in {'f':fclone}

now all that's left to worry about is localizing the global namespaces to modify and pass to the execution.
I'm guessing that could be done something like:

NS = dict( UGE_MODEL_SCRIPT.NS.items() )
NS['f'] = fclone

^is that right or am I missing something??

and after finishing I can just delete that namespace as well as the function clone. (let python's GC handle the rest)

EDIT: btw, IDLE does a good job of showing the arguments: (something ALOT of other python IDEs should do)

function( code, globals[, name[, argdefs[, closure]]])

VS2010 would display the types accepted by those argument-variables (if known)

it's a shame not many IDE developers think about these helpful features.
Eclipse is the only thing I've used that comes close to VS2010, but it's still greatly lacking in information when compared.

anyways, given that, can't I just pass the NS to the globals and call the clone with the arguments??
or is the separate exec layer safer to use when trying to keep everything inside the function secluded to the namespace??

Edited 1 Year Ago by Tcll

I tend to think that the separate exec is not necessary. Try to pass the execution namespace directly when the clone is created.

ok, so I haven't switched the method yet and am still using the first method...

it definitely works... lol:

importing PlPcNr.dat 100% 
Converting from import format...
Error! Check 'session-info.log' for more details.

Traceback (most recent call last):
  File "Z:\media\tcll\copy\Tcll\UMC_workspace\UMC_v3.0a\data\VIEWER.py", line 656, in _ImportModel
    exec '''ugeImportModel()''' in NS, dict( sys.modules['/UGE_GLOBAL_NS/'].items() )
  File "<string>", line 1, in <module>
  File "scripts\HAL_Labs_DAT2.py", line 297, in ugeImportModel
    def _Material(offset,_apply=True):
NameError: global name 'True' is not defined

I've already tried NS['True'] = True among other various methods... heh
nothing changes >_>

A more complete example would be useful. I don't see where it fails. Did you create the clone function with the NS dictionary ?

One thing to try is

NS['__builtins__'] = sys.modules['__builtin__']

(sys.module['builtins'] in python 3)

Edited 1 Year Ago by Gribouillis

ok, so I've ran my tests and ported it over, this works like it should :)
thanks for your help :)

            # credit to Gribouillis for this block:
            # ---
            function = script.ugeImportModel.__class__

            NS = dict( COMMON.UGE_MODEL_SCRIPT.NS.items() ) # clone
            NS['__builtins__'] = sys.modules['__builtin__']

            ugeImportModel = function(script.ugeImportModel.__code__, NS) # clone
            ugeImportModel(filepath.split('.')[-1].lower(),None)
            # ---

now I just get an error saying bu32 is not defined...
that one won't be hard to fix :P

Edited 1 Year Ago by Tcll

Great! A small detail:

>>> from types import FunctionType
>>> FunctionType
<type 'function'>

Using FunctionType instead of function is a little less amateur.

Comments
thanks
This question has already been answered. Start a new discussion instead.