Commit bce8b981 authored by Stefan Behnel's avatar Stefan Behnel

fix ticket #5: mangle private '__xyz' attribute names inside of Python classes

--HG--
rename : tests/run/methodmangling_T5.pyx => tests/run/methodmangling_T5.py
parent 57b5f0cd
...@@ -3800,6 +3800,8 @@ class AttributeNode(ExprNode): ...@@ -3800,6 +3800,8 @@ class AttributeNode(ExprNode):
def analyse_as_python_attribute(self, env, obj_type = None): def analyse_as_python_attribute(self, env, obj_type = None):
if obj_type is None: if obj_type is None:
obj_type = self.obj.type obj_type = self.obj.type
# mangle private '__*' Python attributes used inside of a class
self.attribute = env.mangle_class_private_name(self.attribute)
self.member = self.attribute self.member = self.attribute
self.type = py_object_type self.type = py_object_type
self.is_py_attr = 1 self.is_py_attr = 1
......
...@@ -1222,6 +1222,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1222,6 +1222,7 @@ class FuncDefNode(StatNode, BlockNode):
if self.needs_closure: if self.needs_closure:
lenv = ClosureScope(name=self.entry.name, lenv = ClosureScope(name=self.entry.name,
outer_scope = genv, outer_scope = genv,
parent_scope = env,
scope_name=self.entry.cname) scope_name=self.entry.cname)
else: else:
lenv = LocalScope(name=self.entry.name, lenv = LocalScope(name=self.entry.name,
......
...@@ -329,6 +329,11 @@ class Scope(object): ...@@ -329,6 +329,11 @@ class Scope(object):
return self.mangle(prefix) return self.mangle(prefix)
#return self.parent_scope.mangle(prefix, self.name) #return self.parent_scope.mangle(prefix, self.name)
def mangle_class_private_name(self, name):
if self.parent_scope:
return self.parent_scope.mangle_class_private_name(name)
return name
def next_id(self, name=None): def next_id(self, name=None):
# Return a cname fragment that is unique for this module # Return a cname fragment that is unique for this module
counters = self.global_scope().id_counters counters = self.global_scope().id_counters
...@@ -1535,8 +1540,8 @@ class ClosureScope(LocalScope): ...@@ -1535,8 +1540,8 @@ class ClosureScope(LocalScope):
is_closure_scope = True is_closure_scope = True
def __init__(self, name, scope_name, outer_scope): def __init__(self, name, scope_name, outer_scope, parent_scope=None):
LocalScope.__init__(self, name, outer_scope) LocalScope.__init__(self, name, outer_scope, parent_scope)
self.closure_cname = "%s%s" % (Naming.closure_scope_prefix, scope_name) self.closure_cname = "%s%s" % (Naming.closure_scope_prefix, scope_name)
# def mangle_closure_cnames(self, scope_var): # def mangle_closure_cnames(self, scope_var):
...@@ -1626,9 +1631,22 @@ class PyClassScope(ClassScope): ...@@ -1626,9 +1631,22 @@ class PyClassScope(ClassScope):
is_py_class_scope = 1 is_py_class_scope = 1
def mangle_class_private_name(self, name):
return self.mangle_special_name(name)
def mangle_special_name(self, name):
if name and name.startswith('__') and not name.endswith('__'):
name = EncodedString('_%s%s' % (self.class_name, name))
return name
def lookup_here(self, name):
name = self.mangle_special_name(name)
return ClassScope.lookup_here(self, name)
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0): api = 0, in_pxd = 0, is_cdef = 0):
name = self.mangle_special_name(name)
if type is unspecified_type: if type is unspecified_type:
type = py_object_type type = py_object_type
# Add an entry for a class attribute. # Add an entry for a class attribute.
......
# This file contains tests corresponding to unresolved bugs, # This file contains tests corresponding to unresolved bugs,
# which will be skipped in the normal testing run. # which will be skipped in the normal testing run.
methodmangling_T5
class_attribute_init_values_T18 class_attribute_init_values_T18
numpy_ValueError_T172 numpy_ValueError_T172
unsignedbehaviour_T184 unsignedbehaviour_T184
......
# mode: run
# ticket: 5
class CyTest(object):
"""
>>> cy = CyTest()
>>> '_CyTest__private' in dir(cy)
True
>>> cy._CyTest__private()
8
>>> '__private' in dir(cy)
False
>>> '_CyTest__x' in dir(cy)
True
>>> '__x' in dir(cy)
False
"""
__x = 1
def __private(self): return 8
def get(self):
"""
>>> CyTest().get()
(1, 1, 8)
"""
return self._CyTest__x, self.__x, self.__private()
def get_inner(self):
"""
>>> CyTest().get_inner()
(1, 1, 8)
"""
def get(o):
return o._CyTest__x, o.__x, o.__private()
return get(self)
class CyTestSub(CyTest):
"""
>>> cy = CyTestSub()
>>> '_CyTestSub__private' in dir(cy)
True
>>> cy._CyTestSub__private()
9
>>> '_CyTest__private' in dir(cy)
True
>>> cy._CyTest__private()
8
>>> '__private' in dir(cy)
False
>>> '_CyTestSub__x' in dir(cy)
False
>>> '_CyTestSub__y' in dir(cy)
True
>>> '_CyTest__x' in dir(cy)
True
>>> '__x' in dir(cy)
False
"""
__y = 2
def __private(self): return 9
def get(self):
"""
>>> CyTestSub().get()
(1, 2, 2, 9)
"""
return self._CyTest__x, self._CyTestSub__y, self.__y, self.__private()
def get_inner(self):
"""
>>> CyTestSub().get_inner()
(1, 2, 2, 9)
"""
def get(o):
return o._CyTest__x, o._CyTestSub__y, o.__y, o.__private()
return get(self)
# ticket: 5
# this is ticket #5
__doc__ = u"""
>>> class PyTest(object):
... def __private(self): pass
>>> py = PyTest()
>>> '_PyTest__private' in dir(py)
True
>>> '__private' in dir(py)
False
>>> cy = CyTest()
>>> '_PyTest__private' in dir(cy)
True
>>> '__private' in dir(cy)
False
"""
class CyTest(object):
def __private(self): pass
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment