exec with partial globals
Dave Angel
d at davea.name
Tue Oct 30 09:39:09 EDT 2012
On 10/30/2012 08:57 AM, Helmut Jarausch wrote:
> On Tue, 30 Oct 2012 08:33:38 -0400, Dave Angel wrote:
>
>> On 10/30/2012 08:00 AM, Helmut Jarausch wrote:
>>> Hi,
>>>
>>> I'd like to give the user the ability to enter code which may only rebind
>>> a given set of names but not all ones.
>>> This does NOT work
>>> A=1
>>> B=2
>>> Code=compile('A=7','','exec')
>>> exec(Code,{'A':0})
>>> print("I've got A={}".format(A)) # prints 1
>>>
>>>
>>> How can 'filter' the gobal namespace such that modifying 'A' is allowed
>>> but any attempt to modify 'B' should give an exception.
>>>
>>>
>>> Many thanks for a hint,
>>> Helmut.
>> A=1
>> B=2
>> Code=compile('A=7','','exec')
>> vars = {'A':A}
>> exec(Code, vars)
>> A = vars["A"]
>> print("I've got A={}".format(A)) # prints 1
>>
>> That now prints "I've got A=7"
>>
>> More generally, you could write a loop, copying globals into vars, and
>> another one, copying them back.
>>
>> No idea what you're really after; this is one of the more dangerous
>> things to try.
>>
>> Although you can constrain the globals seen by the code, that code can
>> still use builtins, do imports, delete files, etc.
>>
>> Further, if your user is clever enough, he can do:
>>
>> Code=compile('A=7; print("howdy"); import __main__;
>> __main__.B=42','','exec')
>>
>> What are you really trying to permit him to do? Initialize some
>> variables for you? How about an .ini file ?
> Many thanks Chris, many thanks to Dave.
>
> First, in my application only trusted people will use it.
>
> Here my example. I'd like to update a spreadsheet by data given by another
> spreadsheet. I like to allow to modify only certain columns of the first
> spreadsheet. The update formula and possible conditions are entered at
> run time and the available fields are only known once the spreadsheets
> have been read.
>
> Given spreadsheet S (Source) and D (Destination) as objects (wrapping a
> dictionary) a possible (legal) input would be
>
> D.price= D.price-S.discount
>
> No other fields of 'D' should be modifiable.
>
> Again, I don't need to take actions against a malicious user,
> just take care about a typo or mistake
>
> Thanks again,
> Helmut.
>
If the user will only be modifying fields of specific class instances,
then generate those instances with property wrappers around the readonly
attributes.
If the class were statically defined, you'd do something like:
class MyClass(object):
def __init__(self, data1, data2, data3):
self._data1 = data1
self._data2 = data2
self.data3 = data3 #this one is writable, directly
@property
def data1(self): #this is readonly
return self._data1
@property
def data2(self): #this is readonly
return self._data2
mysrc = MyClass(1,2,3)
mydest = MyClass(4,5,6)
print( mydest.data1, mydest.data2, mydest.data3, "\n") #prints 4,5,6
vars = {"src": mysrc, "dest": mydest}
Code=compile('dest.data3=17','','exec')
exec(Code, vars)
print( mydest.data1, mydest.data2, mydest.data3, "\n") #prints 4,5,17
Now, once you see how to do it statically, you can try to do it dynamically, deciding which attributes need property wrappers, and which ones are plain data.
--
DaveA
More information about the Python-list
mailing list