@@ -357,95 +357,82 @@ def find_disallowed_expression_in_annotation_scope(expr: ast3.expr | None) -> as
357
357
358
358
359
359
class NameMangler (ast3 .NodeTransformer ):
360
- """Mangle all private identifiers within a class body (including nested classes)."""
360
+ """Mangle (nearly) all private identifiers within a class body (including nested classes)."""
361
361
362
- _name_complete : str
363
- _name_trimmed : str
362
+ _classname_complete : str
363
+ _classname_trimmed : str
364
364
_mangle_annotations : bool
365
365
_unmangled_args : set [str ]
366
366
367
- _MANGLE_ARGS : bool = False
367
+ _MANGLE_ARGS : bool = False # ToDo: remove it or make it an option?
368
368
369
369
def __init__ (self , classname : str , mangle_annotations : bool ) -> None :
370
- self ._name_complete = classname
371
- self ._name_trimmed = classname .lstrip ("_" )
370
+ self ._classname_complete = classname
371
+ self ._classname_trimmed = classname .lstrip ("_" )
372
372
self ._mangle_annotations = mangle_annotations
373
373
self ._unmangled_args = set ()
374
374
375
- def _mangle (self , name : str ) -> str :
376
- """Mangle the given name if it looks like a private attribute."""
375
+ def _mangle_name (self , name : str ) -> str :
377
376
if name .startswith ("__" ) and not name .endswith ("__" ):
378
- return f"_{ self ._name_trimmed } { name } "
377
+ return f"_{ self ._classname_trimmed } { name } "
379
378
return name
380
379
381
- def visit_Attribute (self , node : ast3 .Attribute ) -> ast3 .Attribute :
382
- node .attr = self ._mangle (node .attr )
383
- self .generic_visit (node )
384
- return node
385
-
386
- def visit_FunctionDef (self , node : ast3 .FunctionDef ) -> ast3 .FunctionDef :
387
- return self ._visit_funcdef (node )
380
+ def _mangle_slots (self , node : ast3 .ClassDef ) -> None :
381
+ for assign in node .body :
382
+ if isinstance (assign , ast3 .Assign ):
383
+ for target in assign .targets :
384
+ if isinstance (target , ast3 .Name ) and (target .id == "__slots__" ):
385
+ constants : Iterable [ast3 .expr ] = ()
386
+ if isinstance (values := assign .value , ast3 .Constant ):
387
+ constants = (values ,)
388
+ elif isinstance (values , (ast3 .Tuple , ast3 .List )):
389
+ constants = values .elts
390
+ elif isinstance (values , ast3 .Dict ):
391
+ constants = (key for key in values .keys if key is not None )
392
+ for value in constants :
393
+ if isinstance (value , ast3 .Constant ) and isinstance (value .value , str ):
394
+ value .value = self ._mangle_name (value .value )
388
395
389
- def visit_AsyncFunctionDef (self , node : ast3 .AsyncFunctionDef ) -> ast3 .AsyncFunctionDef :
390
- return self ._visit_funcdef (node )
396
+ def visit_ClassDef (self , node : ast3 .ClassDef ) -> ast3 .ClassDef :
397
+ if self ._classname_complete == node .name :
398
+ for stmt in node .body :
399
+ self .visit (stmt )
400
+ self ._mangle_slots (node )
401
+ else :
402
+ for dec in node .decorator_list :
403
+ self .visit (dec )
404
+ NameMangler (node .name , self ._mangle_annotations ).visit (node )
405
+ node .name = self ._mangle_name (node .name )
406
+ return node
391
407
392
408
def _visit_funcdef (self , node : _T_FuncDef ) -> _T_FuncDef :
393
- node .name = self ._mangle (node .name )
394
- if self ._MANGLE_ARGS :
395
- mangler = self
396
- else :
397
- mangler = NameMangler (self ._name_complete , self ._mangle_annotations )
398
- mangler .visit (node .args )
409
+ node .name = self ._mangle_name (node .name )
410
+ if not self ._MANGLE_ARGS :
411
+ self = NameMangler (self ._classname_complete , self ._mangle_annotations )
412
+ self .visit (node .args )
399
413
for dec in node .decorator_list :
400
- mangler .visit (dec )
414
+ self .visit (dec )
401
415
if self ._mangle_annotations and (node .returns is not None ):
402
- mangler .visit (node .returns )
416
+ self .visit (node .returns )
403
417
for stmt in node .body :
404
- mangler .visit (stmt )
418
+ self .visit (stmt )
405
419
return node
406
420
421
+ def visit_FunctionDef (self , node : ast3 .FunctionDef ) -> ast3 .FunctionDef :
422
+ return self ._visit_funcdef (node )
423
+
424
+ def visit_AsyncFunctionDef (self , node : ast3 .AsyncFunctionDef ) -> ast3 .AsyncFunctionDef :
425
+ return self ._visit_funcdef (node )
426
+
407
427
def visit_arg (self , node : ast3 .arg ) -> ast3 .arg :
408
428
if self ._MANGLE_ARGS :
409
- node .arg = self ._mangle (node .arg )
429
+ node .arg = self ._mangle_name (node .arg )
410
430
else :
411
431
self ._unmangled_args .add (node .arg )
412
432
if self ._mangle_annotations and (node .annotation is not None ):
413
433
self .visit (node .annotation )
414
434
return node
415
435
416
- def visit_Name (self , node : Name ) -> Name :
417
- if self ._MANGLE_ARGS or (node .id not in self ._unmangled_args ):
418
- node .id = self ._mangle (node .id )
419
- return node
420
-
421
- def visit_ClassDef (self , node : ast3 .ClassDef ) -> ast3 .ClassDef :
422
- if self ._name_complete == node .name :
423
- for stmt in node .body :
424
- self .visit (stmt )
425
- self ._mangle_slots (node )
426
- else :
427
- for dec in node .decorator_list :
428
- self .visit (dec )
429
- NameMangler (node .name , self ._mangle_annotations ).visit (node )
430
- node .name = self ._mangle (node .name )
431
- return node
432
-
433
- def _mangle_slots (self , node : ast3 .ClassDef ) -> None :
434
- for assign in node .body :
435
- if isinstance (assign , ast3 .Assign ):
436
- for target in assign .targets :
437
- if isinstance (target , ast3 .Name ) and (target .id == "__slots__" ):
438
- constants : Iterable [ast3 .expr ] = ()
439
- if isinstance (values := assign .value , ast3 .Constant ):
440
- constants = (values ,)
441
- elif isinstance (values , (ast3 .Tuple , ast3 .List )):
442
- constants = values .elts
443
- elif isinstance (values , ast3 .Dict ):
444
- constants = (key for key in values .keys if key is not None )
445
- for value in constants :
446
- if isinstance (value , ast3 .Constant ) and isinstance (value .value , str ):
447
- value .value = self ._mangle (value .value )
448
-
449
436
def visit_AnnAssign (self , node : ast3 .AnnAssign ) -> ast3 .AnnAssign :
450
437
self .visit (node .target )
451
438
if node .value is not None :
@@ -454,6 +441,16 @@ def visit_AnnAssign(self, node: ast3.AnnAssign) -> ast3.AnnAssign:
454
441
self .visit (node .annotation )
455
442
return node
456
443
444
+ def visit_Attribute (self , node : ast3 .Attribute ) -> ast3 .Attribute :
445
+ node .attr = self ._mangle_name (node .attr )
446
+ self .generic_visit (node )
447
+ return node
448
+
449
+ def visit_Name (self , node : Name ) -> Name :
450
+ if self ._MANGLE_ARGS or (node .id not in self ._unmangled_args ):
451
+ node .id = self ._mangle_name (node .id )
452
+ return node
453
+
457
454
458
455
class ASTConverter :
459
456
def __init__ (
0 commit comments