Skip to content

Instantly share code, notes, and snippets.

@nitori
Last active January 14, 2023 20:40
Show Gist options
  • Save nitori/2d666af856215d28d12fecd0f36daa68 to your computer and use it in GitHub Desktop.
Save nitori/2d666af856215d28d12fecd0f36daa68 to your computer and use it in GitHub Desktop.
Convert python identifiers to some preselected Unicode characters
import ast
import os
import random
import string
import sys
import unicodedata as ud
class IdentifierTransformer(ast.NodeTransformer):
def __init__(self, char_sets: dict[str, dict[str, list]]):
self.char_sets = char_sets
self._replaced_names = {}
def update_name(self, name: str):
if name in self._replaced_names:
return self._replaced_names[name]
lower_set_to_use = random.choice(list(self.char_sets['lower']))
upper_set_to_use = lower_set_to_use
# try to use the same set for upper case if available
if upper_set_to_use not in self.char_sets['upper']:
upper_set_to_use = random.choice(list(self.char_sets['upper']))
new_name = ''
for char in name:
if char in string.ascii_lowercase:
i = string.ascii_lowercase.index(char)
new_name += self.char_sets['lower'][lower_set_to_use][i]
elif char in string.ascii_uppercase:
i = string.ascii_uppercase.index(char)
new_name += self.char_sets['upper'][upper_set_to_use][i]
else:
new_name += char
self._replaced_names[name] = new_name
return new_name
def visit_ImportFrom(self, node: ast.ImportFrom):
for alias in node.names:
alias.name = self.update_name(alias.name)
if node.module is not None:
node.module = self.update_name(node.module)
return self.generic_visit(node)
def visit_Import(self, node: ast.Import):
for alias in node.names:
alias.name = self.update_name(alias.name)
return self.generic_visit(node)
def visit_Attribute(self, node: ast.Attribute):
node.attr = self.update_name(node.attr)
return self.generic_visit(node)
def visit_Name(self, node: ast.Name):
node.id = self.update_name(node.id)
return self.generic_visit(node)
def visit_FunctionDef(self, node: ast.FunctionDef):
node.name = self.update_name(node.name)
return self.generic_visit(node)
def visit_ClassDef(self, node: ast.ClassDef):
node.name = self.update_name(node.name)
return self.generic_visit(node)
def visit_arg(self, node: ast.arg):
node.arg = self.update_name(node.arg)
return self.generic_visit(node)
def main():
if len(sys.argv) != 3:
print(f'Usage: python {sys.argv[0]} <input_file> <output_file>')
return
char_sets: dict[str, dict[str, list]] = {
'lower': {
'math1': [],
'math2': [],
'math3': [],
'math4': [],
},
'upper': {
'math1': [],
'math2': [],
'math3': [],
},
}
for letter in string.ascii_uppercase:
char_sets['lower']['math1'].append(ud.lookup(f'MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL {letter}'))
char_sets['lower']['math2'].append(ud.lookup(f'MATHEMATICAL SANS-SERIF BOLD SMALL {letter}'))
char_sets['lower']['math3'].append(ud.lookup(f'MATHEMATICAL SANS-SERIF ITALIC SMALL {letter}'))
char_sets['lower']['math4'].append(ud.lookup(f'MATHEMATICAL FRAKTUR SMALL {letter}'))
char_sets['upper']['math1'].append(ud.lookup(f'MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL {letter}'))
char_sets['upper']['math2'].append(ud.lookup(f'MATHEMATICAL SANS-SERIF BOLD CAPITAL {letter}'))
char_sets['upper']['math3'].append(ud.lookup(f'MATHEMATICAL SANS-SERIF ITALIC CAPITAL {letter}'))
# not all exist for FRAKTUR it seems... sad
# char_sets['upper']['math4'].append(ud.lookup(f'MATHEMATICAL FRAKTUR CAPITAL {letter}'))
with open(sys.argv[1], 'r', encoding='utf-8') as f:
code = f.read()
tree = ast.parse(code)
new_tree = ast.fix_missing_locations(IdentifierTransformer(char_sets).visit(tree))
if os.path.exists(sys.argv[2]):
if input(f'File {sys.argv[2]} exists. Overwrite? [y/N] ').lower() != 'y':
print('Aborting.')
return
with open(sys.argv[2], 'w', encoding='utf-8') as f:
f.write(ast.unparse(new_tree))
if __name__ == '__main__':
main()
@nitori
Copy link
Author

nitori commented Jan 10, 2023

Applied on this: https://gist.github.com/nitori/e9704b249526296c1e5701cd9822cbf7

import ๐˜€๐˜†๐˜€

def ๐”ฆ๐”ซ๐”ฑ_๐”ฐ๐”ฒ๐” ๐” ๐”ข๐”ข๐”ก๐”ฐ(๐” : ๐™จ๐™ฉ๐™ง):
    try:
        ๐˜ช๐˜ฏ๐˜ต(๐” )
    except ๐˜๐˜ข๐˜ญ๐˜ถ๐˜ฆ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ:
        return False
    return True
๐˜ค๐˜ฉ๐˜ข๐˜ณ๐˜ด = [๐˜ค๐˜ฉ๐˜ณ(๐”ซ) for ๐”ซ in ๐™ง๐™–๐™ฃ๐™œ๐™š(๐˜€๐˜†๐˜€.๐™ข๐™–๐™ญ๐™ช๐™ฃ๐™ž๐™˜๐™ค๐™™๐™š + 1)]
๐”ซ๐”ฒ๐”ช๐”ข๐”ฏ๐”ฆ๐” ๐”ฐ = {๐”  for ๐”  in ๐˜ค๐˜ฉ๐˜ข๐˜ณ๐˜ด if ๐” .๐—ถ๐˜€๐—ป๐˜‚๐—บ๐—ฒ๐—ฟ๐—ถ๐—ฐ()}
๐˜ฅ๐˜ช๐˜จ๐˜ช๐˜ต๐˜ด = {๐”  for ๐”  in ๐˜ค๐˜ฉ๐˜ข๐˜ณ๐˜ด if ๐” .๐™ž๐™จ๐™™๐™ž๐™œ๐™ž๐™ฉ()}
๐˜ฅ๐˜ฆ๐˜ค๐˜ช๐˜ฎ๐˜ข๐˜ญ๐˜ด = {๐”  for ๐”  in ๐˜ค๐˜ฉ๐˜ข๐˜ณ๐˜ด if ๐” .๐˜ช๐˜ด๐˜ฅ๐˜ฆ๐˜ค๐˜ช๐˜ฎ๐˜ข๐˜ญ()}
๐—ฝ๐—ฟ๐—ถ๐—ป๐˜('No. numerics:', ๐˜ญ๐˜ฆ๐˜ฏ(๐”ซ๐”ฒ๐”ช๐”ข๐”ฏ๐”ฆ๐” ๐”ฐ))
๐—ฝ๐—ฟ๐—ถ๐—ป๐˜('No. digits:', ๐˜ญ๐˜ฆ๐˜ฏ(๐˜ฅ๐˜ช๐˜จ๐˜ช๐˜ต๐˜ด))
๐—ฝ๐—ฟ๐—ถ๐—ป๐˜('No. decimals:', ๐˜ญ๐˜ฆ๐˜ฏ(๐˜ฅ๐˜ฆ๐˜ค๐˜ช๐˜ฎ๐˜ข๐˜ญ๐˜ด))
๐—ฝ๐—ฟ๐—ถ๐—ป๐˜('numerics โŠƒ digits โŠƒ decimals:', ๐”ซ๐”ฒ๐”ช๐”ข๐”ฏ๐”ฆ๐” ๐”ฐ > ๐˜ฅ๐˜ช๐˜จ๐˜ช๐˜ต๐˜ด > ๐˜ฅ๐˜ฆ๐˜ค๐˜ช๐˜ฎ๐˜ข๐˜ญ๐˜ด)
๐—ฝ๐—ฟ๐—ถ๐—ป๐˜('int() on numerics:', ๐”ž๐”ฉ๐”ฉ((๐”ฆ๐”ซ๐”ฑ_๐”ฐ๐”ฒ๐” ๐” ๐”ข๐”ข๐”ก๐”ฐ(๐” ) for ๐”  in ๐”ซ๐”ฒ๐”ช๐”ข๐”ฏ๐”ฆ๐” ๐”ฐ)))
๐—ฝ๐—ฟ๐—ถ๐—ป๐˜('int() on digits:', ๐”ž๐”ฉ๐”ฉ((๐”ฆ๐”ซ๐”ฑ_๐”ฐ๐”ฒ๐” ๐” ๐”ข๐”ข๐”ก๐”ฐ(๐” ) for ๐”  in ๐˜ฅ๐˜ช๐˜จ๐˜ช๐˜ต๐˜ด)))
๐—ฝ๐—ฟ๐—ถ๐—ป๐˜('int() on decimals:', ๐”ž๐”ฉ๐”ฉ((๐”ฆ๐”ซ๐”ฑ_๐”ฐ๐”ฒ๐” ๐” ๐”ข๐”ข๐”ก๐”ฐ(๐” ) for ๐”  in ๐˜ฅ๐˜ฆ๐˜ค๐˜ช๐˜ฎ๐˜ข๐˜ญ๐˜ด)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment