Skip to content

Commit 7f619a3

Browse files
committed
[GR-27405] Mangle private attribute name in parser.
PullRequest: graalpython/1418
2 parents 6850d6a + 12d8e62 commit 7f619a3

File tree

25 files changed

+547
-156
lines changed

25 files changed

+547
-156
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -385,19 +385,19 @@ public void testGettersSetters() throws Throwable {
385385
assertTrue(x.hasWriteSideEffects());
386386
assertTrue(x.isReadable());
387387
assertTrue(x.isWritable());
388-
assertEquals(0, p.getProperty("__nx").asInt());
388+
assertEquals(0, p.getProperty("_P__nx").asInt());
389389
assertEquals("None", x.toDisplayString());
390-
assertEquals(1, p.getProperty("__nx").asInt());
390+
assertEquals(1, p.getProperty("_P__nx").asInt());
391391
x.set(42);
392-
assertEquals(2, p.getProperty("__nx").asInt());
392+
assertEquals(2, p.getProperty("_P__nx").asInt());
393393
assertEquals("42", x.toDisplayString());
394-
assertEquals(3, p.getProperty("__nx").asInt());
394+
assertEquals(3, p.getProperty("_P__nx").asInt());
395395
DebugValue y = p.getProperty("y");
396396
assertTrue(y.hasReadSideEffects());
397397
assertFalse(y.hasWriteSideEffects());
398398
assertTrue(y.isReadable());
399399
assertTrue(y.isWritable());
400-
DebugValue ny = p.getProperty("__ny");
400+
DebugValue ny = p.getProperty("_P__ny");
401401
assertEquals(0, ny.asInt());
402402
y.set(24);
403403
assertEquals("24", y.toDisplayString());
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
def public_method():
41+
print("I'm public")
42+
43+
def __private_method():
44+
print("I'm private")

graalpython/com.oracle.graal.python.test/src/tests/test_parser.py

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,277 @@ def test_invalid_return_statement():
246246
assert_raise_syntax_error("class A: return 10\n", "'return' outside function")
247247

248248

249+
def test_mangled_class_property():
250+
class P:
251+
__property = 1
252+
def get_property(self):
253+
return self.__property
254+
def get_mangled_property(self):
255+
return self._P__property
256+
257+
p = P()
258+
assert P._P__property == 1
259+
assert "_P__property" in dir(P)
260+
assert "__property" not in dir(P)
261+
assert p._P__property == 1
262+
assert "_P__property" in dir(p)
263+
assert "__property" not in dir(p)
264+
assert p.get_property() == 1
265+
assert p.get_mangled_property() == 1
266+
267+
try:
268+
print(P.__property)
269+
except AttributeError as ae:
270+
pass
271+
else:
272+
assert False, "AttributeError was not raised"
273+
274+
try:
275+
print(p.__property)
276+
except AttributeError as ae:
277+
pass
278+
else:
279+
assert False, "AttributeError was not raised"
280+
281+
class B:
282+
__ = 2
283+
284+
b = B()
285+
assert B.__ == 2
286+
assert "__" in dir(B)
287+
assert b.__ == 2
288+
assert "__" in dir(b)
289+
290+
class C:
291+
___ = 3
292+
293+
c = C()
294+
assert C.___ == 3
295+
assert "___" in dir(C)
296+
assert c.___ == 3
297+
assert "___" in dir(c)
298+
299+
class D:
300+
_____ = 4
301+
302+
d = D()
303+
assert D._____ == 4
304+
assert "_____" in dir(D)
305+
assert d._____ == 4
306+
assert "_____" in dir(d)
307+
308+
class E:
309+
def __init__(self, value):
310+
self.__value = value
311+
def getValue(self):
312+
return self.__value
313+
314+
e = E(5)
315+
assert e.getValue() == 5
316+
assert e._E__value == 5
317+
assert "_E__value" in dir(e)
318+
assert "__value" not in dir(e)
319+
320+
class F:
321+
def __init__(self, value):
322+
self.__a = value
323+
def get(self):
324+
return self.__a
325+
326+
f = F(5)
327+
assert "_F__a" in dir(f)
328+
assert "__a" not in dir(f)
329+
330+
def test_underscore_class_name():
331+
class _:
332+
__a = 1
333+
334+
assert _.__a == 1
335+
assert "__a" in dir(_)
336+
337+
338+
def test_mangled_class_method():
339+
class A:
340+
___sound = "hello"
341+
def __hello(self):
342+
return self.___sound
343+
def hello(self):
344+
return self.__hello()
345+
346+
a = A()
347+
assert "_A__hello" in dir(A)
348+
assert "__hello" not in dir(A)
349+
assert a.hello() == 'hello'
350+
351+
try:
352+
print(A.__hello)
353+
except AttributeError as ae:
354+
pass
355+
else:
356+
assert False, "AttributeError was not raised"
357+
358+
try:
359+
print(a.__hello)
360+
except AttributeError as ae:
361+
pass
362+
else:
363+
assert False, "AttributeError was not raised"
364+
365+
def test_mangled_private_class():
366+
class __P:
367+
__property = 1
368+
369+
p = __P()
370+
assert __P._P__property == 1
371+
assert "_P__property" in dir(__P)
372+
assert "__property" not in dir(__P)
373+
assert p._P__property == 1
374+
assert "_P__property" in dir(p)
375+
assert "__property" not in dir(p)
376+
377+
class __:
378+
__property = 2
379+
380+
p = __()
381+
assert __.__property == 2
382+
assert "__property" in dir(__)
383+
assert p.__property == 2
384+
assert "__property" in dir(p)
385+
386+
387+
class _____Testik__:
388+
__property = 3
389+
390+
p = _____Testik__()
391+
assert _____Testik__._Testik____property == 3
392+
assert "_Testik____property" in dir(_____Testik__)
393+
assert "__property" not in dir(_____Testik__)
394+
assert p._Testik____property == 3
395+
assert "_Testik____property" in dir(p)
396+
assert "__property" not in dir(p)
397+
398+
def test_mangled_import():
399+
class X:
400+
def fn(self):
401+
import __mangled_module
402+
403+
assert '_X__mangled_module' in X.fn.__code__.co_varnames
404+
assert '__mangled_module' not in X.fn.__code__.co_varnames
405+
406+
407+
def test_mangled_params():
408+
def xf(__param):
409+
return __param
410+
assert '__param' in xf.__code__.co_varnames
411+
assert xf(10) == 10
412+
413+
class X:
414+
def m1(self, __param):
415+
return __param
416+
def m2(self, *__arg):
417+
return __arg
418+
def m3(self, **__kw):
419+
return __kw
420+
421+
422+
assert '_X__param' in X.m1.__code__.co_varnames
423+
assert '__param' not in X.m1.__code__.co_varnames
424+
assert X().m1(11) == 11
425+
426+
assert '_X__arg' in X.m2.__code__.co_varnames
427+
assert '__arg' not in X.m2.__code__.co_varnames
428+
assert X().m2(1, 2, 3) == (1,2,3)
429+
430+
assert '_X__kw' in X.m3.__code__.co_varnames
431+
assert '__kw' not in X.m3.__code__.co_varnames
432+
assert X().m3(a = 1, b = 2) == {'a':1, 'b':2}
433+
434+
def test_mangled_local_vars():
435+
class L:
436+
def fn(self, i):
437+
__result = 0
438+
for __index in range (1, i + 1):
439+
__result += __index
440+
return __result
441+
442+
assert '_L__result' in L.fn.__code__.co_varnames
443+
assert '__result' not in L.fn.__code__.co_varnames
444+
assert '_L__index' in L.fn.__code__.co_varnames
445+
assert '__index' not in L.fn.__code__.co_varnames
446+
assert L().fn(5) == 15
447+
448+
449+
def test_mangled_inner_function():
450+
def find_code_object(code_object, name):
451+
import types
452+
for object in code_object.co_consts:
453+
if type(object) == types.CodeType and object.co_name == name:
454+
return object
455+
456+
class L:
457+
def fn(self, i):
458+
def __help(__i):
459+
__result = 0
460+
for __index in range (1, __i + 1):
461+
__result += __index
462+
return __result
463+
return __help(i)
464+
465+
assert '_L__help' in L.fn.__code__.co_varnames
466+
assert '__help' not in L.fn.__code__.co_varnames
467+
468+
# CPython has stored as name of the code object the non mangle name. The question is, if this is right.
469+
co = find_code_object(L.fn.__code__, '__help')
470+
if co is None:
471+
co = find_code_object(L.fn.__code__, '_L__help')
472+
assert co is not None
473+
assert '_L__result' in co.co_varnames
474+
assert '__result' not in co.co_varnames
475+
assert '_L__index' in co.co_varnames
476+
assert '__index' not in co.co_varnames
477+
assert L().fn(5) == 15
478+
479+
480+
def test_mangled_default_value_param():
481+
class D:
482+
def fn(self, __default = 5):
483+
return __default
484+
485+
assert D().fn(_D__default = 11) == 11
486+
487+
try:
488+
D().fn(__default = 11)
489+
except TypeError as ae:
490+
pass
491+
else:
492+
assert False, "TypeError was not raised"
493+
494+
def test_method_decorator():
495+
class S:
496+
def __init__(self, value):
497+
self.value = value
498+
@property
499+
def __ser(self):
500+
return self.value
501+
@__ser.setter
502+
def __ser(self, value):
503+
self.value = value
504+
505+
s = S(10)
506+
assert s.value == 10
507+
assert s._S__ser == 10
508+
assert '_S__ser' in dir(S)
509+
assert '_S__ser' in dir(s)
510+
assert '__ser' not in dir(S)
511+
assert '__ser' not in dir(s)
512+
513+
s.value = 11
514+
assert s._S__ser == 11
515+
516+
s._S__ser = 12
517+
assert s.value == 12
518+
519+
s.__ser = 13
520+
assert s.value == 12
521+
assert s.__ser == 13
522+
assert s._S__ser == 12

graalpython/com.oracle.graal.python.test/testData/goldenFiles/GeneratorAndCompForTests/class01.tast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ ModuleRootNode Name: <module 'class01'> SourceSection: [0,192]`class OrderedDict
8686
Frame: [1,root,Illegal]
8787
GetAttributeNodeGen SourceSection: [68,79]`self.__root`
8888
GetFixedAttributeNodeGen SourceSection: None
89-
Key: __root
89+
Key: _OrderedDict__root
9090
CachedDispatchFirst SourceSection: None
9191
LookupAndCallBinaryNodeGen SourceSection: None
9292
Op: __getattribute__

graalpython/com.oracle.graal.python.test/testData/testFiles/RuntimeFileTests/_collections_abc.scope

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ Scope: []
105105
FreeVars: Empty
106106
Scope: MutableMapping
107107
Kind: Class
108-
FrameDescriptor: [__setitem__, pop, __marker, setdefault, clear, update, __slots__, popitem, __delitem__]
108+
FrameDescriptor: [__setitem__, pop, _MutableMapping__marker, setdefault, clear, update, __slots__, popitem, __delitem__]
109109
CellVars: Empty
110110
FreeVars: Empty
111111
Scope: setdefault

graalpython/com.oracle.graal.python.test/testData/testFiles/RuntimeFileTests/_collections_abc.tast

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9033,7 +9033,7 @@ ModuleRootNode Name: <module '_collections_abc'> SourceSection: [0,26444]`# Copy
90339033
CelVars: None
90349034
FreeVars: None
90359035
NeedsCellFrame: False
9036-
FrameDescriptor: 9 slots [__slots__, __setitem__, __delitem__, __marker, pop, popitem, clear, update, setdefault]
9036+
FrameDescriptor: 9 slots [__slots__, __setitem__, __delitem__, _MutableMapping__marker, pop, popitem, clear, update, setdefault]
90379037
ExecutionSlots:
90389038
FreeVarsSlots: None
90399039
CellVarsSlots: None
@@ -9220,7 +9220,7 @@ ModuleRootNode Name: <module '_collections_abc'> SourceSection: [0,26444]`# Copy
92209220
Index: 0
92219221
StringLiteralNode SourceSection: None
92229222
ReadGlobalOrBuiltinNodeGen SourceSection: None
9223-
Identifier: __marker
9223+
Identifier: _MutableMapping__marker
92249224
ReadAttributeFromObjectNotTypeNodeGen SourceSection: None
92259225
KwArguments: None
92269226
Documentation: StringLiteralNode: `D.pop(k[,d]) -> v, r...`
@@ -9290,7 +9290,7 @@ ModuleRootNode Name: <module '_collections_abc'> SourceSection: [0,26444]`# Copy
92909290
ReadVariableFromFrameNodeGen SourceSection: None
92919291
GetAttributeNodeGen SourceSection: [20511,20524]`self.__marker`
92929292
GetFixedAttributeNodeGen SourceSection: None
9293-
Key: __marker
9293+
Key: _MutableMapping__marker
92949294
CachedDispatchFirst SourceSection: None
92959295
LookupAndCallBinaryNodeGen SourceSection: None
92969296
Op: __getattribute__

0 commit comments

Comments
 (0)