Download python/watermark_stripper.py from Snapkitty/tlm-jxcl: direct link, hf CLI and curl.
- Browser
- Download file 3.14 kB
-
https://huggingface.co/Snapkitty/tlm-jxcl/resolve/main/python/watermark_stripper.py
- Command line
-
hf download hf://Snapkitty/tlm-jxcl/python/watermark_stripper.py
-
curl -L -o watermark_stripper.py https://huggingface.co/Snapkitty/tlm-jxcl/resolve/main/python/watermark_stripper.py
3.14 kB
| import ast | |
| import hashlib | |
| from typing import Dict, Set | |
| class WatermarkStripper(ast.NodeTransformer): | |
| """ | |
| AST-based watermark / fingerprint stripper + light name obfuscator. | |
| - Renames user-defined functions, classes, and arguments | |
| - Removes leading docstrings from functions and classes | |
| - Preserves builtins, dunders, and imports | |
| """ | |
| def __init__(self, prefix: str = "_w"): | |
| self.prefix = prefix | |
| self.name_map: Dict[str, str] = {} | |
| self.counter = 0 | |
| self.protected: Set[str] = { | |
| "print", "len", "range", "list", "dict", "set", "tuple", | |
| "str", "int", "float", "bool", "None", "True", "False", | |
| "self", "cls", "super", "object", "type", "Exception", | |
| "__init__", "__name__", "__main__", "__file__", "__doc__", | |
| "__all__", "__dict__", "__class__", "__module__", | |
| } | |
| def _get_obfuscated_name(self, original: str) -> str: | |
| if original in self.protected or original.startswith("__"): | |
| return original | |
| if original not in self.name_map: | |
| digest = hashlib.md5(original.encode()).hexdigest()[:6] | |
| self.name_map[original] = f"{self.prefix}{self.counter}_{digest}" | |
| self.counter += 1 | |
| return self.name_map[original] | |
| def visit_FunctionDef(self, node: ast.FunctionDef): | |
| node.name = self._get_obfuscated_name(node.name) | |
| if (node.body and isinstance(node.body[0], ast.Expr) | |
| and isinstance(node.body[0].value, ast.Constant) | |
| and isinstance(node.body[0].value.value, str)): | |
| node.body.pop(0) | |
| return self.generic_visit(node) | |
| def visit_ClassDef(self, node: ast.ClassDef): | |
| node.name = self._get_obfuscated_name(node.name) | |
| if (node.body and isinstance(node.body[0], ast.Expr) | |
| and isinstance(node.body[0].value, ast.Constant) | |
| and isinstance(node.body[0].value.value, str)): | |
| node.body.pop(0) | |
| return self.generic_visit(node) | |
| def visit_arg(self, node: ast.arg): | |
| node.arg = self._get_obfuscated_name(node.arg) | |
| return self.generic_visit(node) | |
| def visit_Name(self, node: ast.Name): | |
| if isinstance(node.ctx, (ast.Load, ast.Store, ast.Del)): | |
| if node.id in self.name_map: | |
| node.id = self.name_map[node.id] | |
| return node | |
| def visit_Attribute(self, node: ast.Attribute): | |
| self.generic_visit(node) | |
| return node | |
| def sanitize_code(source_code: str) -> str: | |
| tree = ast.parse(source_code) | |
| stripper = WatermarkStripper() | |
| transformed = stripper.visit(tree) | |
| ast.fix_missing_locations(transformed) | |
| return ast.unparse(transformed) | |
| if __name__ == "__main__": | |
| sample = ''' | |
| def calculate_sum(a, b): | |
| """This is a watermark docstring.""" | |
| return a + b | |
| class Calculator: | |
| """Class-level watermark.""" | |
| def multiply(self, x, y): | |
| return x * y | |
| result = calculate_sum(3, 4) | |
| print(result) | |
| ''' | |
| print("=== ORIGINAL ===") | |
| print(sample) | |
| print("\n=== STRIPPED / OBFUSCATED ===") | |
| print(sanitize_code(sample)) | |