Skip to content

Commit

Permalink
Fixes brython-dev#673 : Brython does not mangle private attribute names
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre Quentel committed Sep 19, 2017
1 parent 8132b7e commit 0bfc056
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 19 deletions.
6 changes: 3 additions & 3 deletions www/src/Lib/browser/local_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

has_local_storage = hasattr(window, 'localStorage')

class __UnProvided():
class _UnProvided():
pass

class LocalStorage():
Expand Down Expand Up @@ -55,10 +55,10 @@ def get(self, key, default=None):
raise TypeError("key must be string")
return self.store.getItem(key) or default

def pop(self, key, default=__UnProvided()):
def pop(self, key, default=_UnProvided()):
if (not isinstance(key, str)):
raise TypeError("key must be string")
if type(default) is __UnProvided:
if type(default) is _UnProvided:
ret = self.get(key)
del self[key] # will throw key error if doesn't exist
return ret
Expand Down
6 changes: 3 additions & 3 deletions www/src/Lib/browser/object_storage.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json

class __UnProvided():
class _UnProvided():
pass


Expand All @@ -26,8 +26,8 @@ def get(self, key, default=None):
return self.storage[json.dumps(key)]
return default

def pop(self, key, default=__UnProvided()):
if type(default) is __UnProvided or json.dumps(key) in self.storage:
def pop(self, key, default=_UnProvided()):
if type(default) is _UnProvided or json.dumps(key) in self.storage:
return json.loads(self.storage.pop(json.dumps(key)))
return default

Expand Down
6 changes: 3 additions & 3 deletions www/src/Lib/sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def getrecursionlimit():
version += " (default, %s) \n[Javascript 1.5] on Brython" % __BRYTHON__.compiled_date
hexversion = 0x03000000 # python 3.0

class __version_info(object):
class _version_info(object):
def __init__(self, version_info):
self.version_info = version_info
self.major = version_info[0]
Expand Down Expand Up @@ -143,12 +143,12 @@ def __ne__(self,other):


#eventually this needs to be the real python version such as 3.0, 3.1, etc
version_info=__version_info(__BRYTHON__.version_info)
version_info = _version_info(__BRYTHON__.version_info)

class _implementation:
def __init__(self):
self.name='brython'
self.version = __version_info(__BRYTHON__.implementation)
self.version = _version_info(__BRYTHON__.implementation)
self.hexversion = self.version.hexversion()
self.cache_tag=None

Expand Down
16 changes: 13 additions & 3 deletions www/src/brython.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ $B.regexIdentifier=/^(?:[\$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C
__BRYTHON__.implementation=[3,3,4,'dev',0]
__BRYTHON__.__MAGIC__="3.3.4"
__BRYTHON__.version_info=[3,3,0,'alpha',0]
__BRYTHON__.compiled_date="2017-09-19 15:43:35.611851"
__BRYTHON__.compiled_date="2017-09-19 18:19:02.668328"
__BRYTHON__.builtin_module_names=["posix","sys","errno","time","_ajax","_base64","_jsre","_multiprocessing","_posixsubprocess","_profile","_svg","_sys","builtins","dis","hashlib","json","long_int","math","modulefinder","random","_abcoll","_codecs","_collections","_csv","_functools","_imp","_io","_random","_socket","_sre","_string","_struct","_sysconfigdata","_testcapi","_thread","_warnings","_weakref"]

;(function($B){var js,$pos,res,$op
Expand Down Expand Up @@ -995,7 +995,10 @@ this.default_list=[]
this.other_args=null
this.other_kw=null
this.after_star=[]
this.set_name=function(name){var id_ctx=new $IdCtx(this,name)
this.set_name=function(name){try{name=$mangle(name,this.parent.tree[0])}catch(err){console.log(err)
console.log('parent',this.parent)
throw err}
var id_ctx=new $IdCtx(this,name)
this.name=name
this.id=this.scope.id+'_'+name
this.id=this.id.replace(/\./g,'_')
Expand Down Expand Up @@ -1602,7 +1605,7 @@ return ''}}
function $IdCtx(C,value){
this.type='id'
this.toString=function(){return '(id) '+this.value+':'+(this.tree||'')}
this.value=value
this.value=$mangle(value,C)
this.parent=C
this.tree=[]
C.tree[C.tree.length]=this
Expand Down Expand Up @@ -2644,6 +2647,12 @@ function $to_js(tree,sep){if(sep===undefined){sep=','}
return tree.map($to_js_map).join(sep)}
function $arbo(ctx){while(ctx.parent!=undefined){ctx=ctx.parent}
return ctx}
function $mangle(name,C){
if(name.substr(0,2)=="__" && name.substr(name.length-2)!=="__"){var klass=null,scope=$get_scope(C)
while(true){if(scope.ntype=="module"){return name}
else if(scope.ntype=="class"){var class_name=scope.C.tree[0].name
while(class_name.charAt(0)=='_'){class_name=class_name.substr(1)}
return '_' + class_name + name}else{if(scope.parent && scope.parent.C){scope=$get_scope(scope.C.tree[0])}else{return name}}}}else{return name}}
function $transition(C,token){
switch(C.type){case 'abstract_expr':
switch(token){case 'id':
Expand Down Expand Up @@ -2740,6 +2749,7 @@ $_SyntaxError(C,'token '+token+' after '+C)
case 'attribute':
if(token==='id'){var name=arguments[2]
if(noassign[name]===true){$_SyntaxError(C,["cannot assign to "+name])}
name=$mangle(name,C)
C.name=name
return C.parent}
$_SyntaxError(C,token)
Expand Down
18 changes: 14 additions & 4 deletions www/src/brython_dist.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion www/src/brython_stdlib.js

Large diffs are not rendered by default.

31 changes: 30 additions & 1 deletion www/src/py2js.js
Original file line number Diff line number Diff line change
Expand Up @@ -1941,6 +1941,13 @@ function $DefCtx(context){
this.after_star = []

this.set_name = function(name){
try{
name = $mangle(name, this.parent.tree[0])
}catch(err){
console.log(err)
console.log('parent', this.parent)
throw err
}
var id_ctx = new $IdCtx(this,name)
this.name = name
this.id = this.scope.id+'_'+name
Expand Down Expand Up @@ -3163,7 +3170,7 @@ function $IdCtx(context,value){

this.type = 'id'
this.toString = function(){return '(id) '+this.value+':'+(this.tree||'')}
this.value = value
this.value = $mangle(value, context)
this.parent = context
this.tree = []
context.tree[context.tree.length]=this
Expand Down Expand Up @@ -5383,6 +5390,27 @@ function $arbo(ctx){
return ctx
}

function $mangle(name, context){
// If name starts with __ and doesn't end with __, and if it is defined
// in a class, "mangle" it, ie preprend _<classname>
if(name.substr(0, 2)=="__" && name.substr(name.length-2)!=="__"){
var klass = null,
scope = $get_scope(context)
while(true){
if(scope.ntype=="module"){return name}
else if(scope.ntype=="class"){
var class_name = scope.context.tree[0].name
while(class_name.charAt(0)=='_'){class_name=class_name.substr(1)}
return '_' + class_name + name
}else{
if(scope.parent && scope.parent.context){
scope = $get_scope(scope.context.tree[0])
}else{return name}
}
}
}else{return name}
}

// Function called in function $tokenise for each token found in the
// Python source code

Expand Down Expand Up @@ -5507,6 +5535,7 @@ function $transition(context,token){
var name = arguments[2]
if(noassign[name]===true){$_SyntaxError(context,
["cannot assign to "+name])}
name = $mangle(name, context)
context.name=name
return context.parent
}
Expand Down
2 changes: 1 addition & 1 deletion www/src/version_info.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__BRYTHON__.implementation = [3, 3, 4, 'dev', 0]
__BRYTHON__.__MAGIC__ = "3.3.4"
__BRYTHON__.version_info = [3, 3, 0, 'alpha', 0]
__BRYTHON__.compiled_date = "2017-09-19 15:43:35.611851"
__BRYTHON__.compiled_date = "2017-09-19 18:19:02.668328"
__BRYTHON__.builtin_module_names = ["posix","sys", "errno", "time","_ajax",
"_base64",
"_jsre",
Expand Down
44 changes: 44 additions & 0 deletions www/tests/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,50 @@ def x(self):
assert 0.1 is 0.1
assert not(1 is 1.0)

# issue 673
class A:
__z = 7
def __init__(self):
self.__x = 20

a = A()
assert a._A__x == 20
assert a._A__z == 7


class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)

def update(self, iterable):
for item in iterable:
self.items_list.append(item)

__update = update # private copy of original update() method

class MappingSubclass(Mapping):

def update(self, keys, values):
# provides new signature for update()
# but does not break __init__()
for item in zip(keys, values):
self.items_list.append(item)

mapping = Mapping(range(3))
mapping.update(range(7, 10))
assert mapping.items_list == [0, 1, 2, 7, 8, 9]

map2 = MappingSubclass(range(3))
map2.update(['a', 'b'], [8, 9])
assert map2.items_list == [0, 1, 2, ('a', 8), ('b', 9)]

class B:
def __print(self, name):
return name

assert B()._B__print('ok') == 'ok'

# issue 680
class A:
def __getattribute__(self, name):
Expand Down

0 comments on commit 0bfc056

Please sign in to comment.