AutoCython-zhang 2.3.6__tar.gz → 2.3.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython/_version.py +1 -1
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython/obfuscate.py +198 -80
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/PKG-INFO +7 -5
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/PKG-INFO +7 -5
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/README.md +6 -4
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/pyproject.toml +1 -1
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython/AutoCython.py +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython/__init__.py +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython/compile.py +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython/run_tasks.py +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython/tools.py +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/SOURCES.txt +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/dependency_links.txt +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/entry_points.txt +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/requires.txt +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/top_level.txt +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/LICENSE +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/MANIFEST.in +0 -0
- {autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/setup.cfg +0 -0
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"""AST 混淆模块:去 docstring
|
|
1
|
+
"""AST 混淆模块:去 docstring、局部变量重命名、字符串加密、常量折叠、控制流平坦化、虚假分支。
|
|
2
|
+
|
|
3
|
+
注解(annotation)默认完整保留,以兼容 FastAPI/Pydantic/dataclass/attrs 等依赖运行时
|
|
4
|
+
``__annotations__`` 的框架;字符串与常量混淆会跳过 annotation 子树。
|
|
5
|
+
"""
|
|
2
6
|
import ast
|
|
3
7
|
import copy
|
|
4
8
|
import hashlib
|
|
@@ -6,6 +10,16 @@ import random
|
|
|
6
10
|
|
|
7
11
|
_UNSAFE_CALLS = frozenset({'globals', 'locals', 'eval', 'exec', 'vars'})
|
|
8
12
|
_PATTERN_SKIP_ATTR = '_autocython_skip_literal_obf'
|
|
13
|
+
_SCOPE_BOUNDARY_NODES = (
|
|
14
|
+
ast.FunctionDef,
|
|
15
|
+
ast.AsyncFunctionDef,
|
|
16
|
+
ast.ClassDef,
|
|
17
|
+
ast.Lambda,
|
|
18
|
+
ast.ListComp,
|
|
19
|
+
ast.SetComp,
|
|
20
|
+
ast.DictComp,
|
|
21
|
+
ast.GeneratorExp,
|
|
22
|
+
)
|
|
9
23
|
|
|
10
24
|
|
|
11
25
|
def _has_unsafe_call(node):
|
|
@@ -21,14 +35,18 @@ def _has_unsafe_call(node):
|
|
|
21
35
|
|
|
22
36
|
|
|
23
37
|
def _walk_no_nested_scope(body):
|
|
24
|
-
"""遍历 body
|
|
38
|
+
"""遍历 body 中的节点,不穿透嵌套词法作用域。
|
|
39
|
+
|
|
40
|
+
Python 3 中 lambda 与各类 comprehension 也会创建独立词法作用域。
|
|
41
|
+
局部变量重命名若穿透这些节点,容易把 ``lambda e: ...`` 的参数
|
|
42
|
+
与外层 ``for e in ...`` 的重命名混在一起,生成
|
|
43
|
+
``free variable ... referenced before assignment`` 一类运行时错误。
|
|
44
|
+
"""
|
|
25
45
|
for node in body:
|
|
26
46
|
yield node
|
|
27
|
-
if isinstance(node,
|
|
47
|
+
if isinstance(node, _SCOPE_BOUNDARY_NODES):
|
|
28
48
|
continue
|
|
29
49
|
for child in ast.iter_child_nodes(node):
|
|
30
|
-
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
|
31
|
-
continue
|
|
32
50
|
yield from _walk_no_nested_scope([child])
|
|
33
51
|
|
|
34
52
|
|
|
@@ -49,6 +67,34 @@ def _mark_pattern_constants(pattern):
|
|
|
49
67
|
setattr(child, _PATTERN_SKIP_ATTR, True)
|
|
50
68
|
|
|
51
69
|
|
|
70
|
+
def _mark_annotation_constants(tree):
|
|
71
|
+
"""标记 annotation 子树内常量,避免字符串加密/常量折叠改变运行时注解语义。"""
|
|
72
|
+
|
|
73
|
+
def mark(node):
|
|
74
|
+
if node is None:
|
|
75
|
+
return
|
|
76
|
+
for child in ast.walk(node):
|
|
77
|
+
if isinstance(child, ast.Constant):
|
|
78
|
+
setattr(child, _PATTERN_SKIP_ATTR, True)
|
|
79
|
+
|
|
80
|
+
def mark_arg_annotations(args):
|
|
81
|
+
all_args = args.posonlyargs + args.args + args.kwonlyargs
|
|
82
|
+
if args.vararg:
|
|
83
|
+
all_args.append(args.vararg)
|
|
84
|
+
if args.kwarg:
|
|
85
|
+
all_args.append(args.kwarg)
|
|
86
|
+
for arg in all_args:
|
|
87
|
+
mark(arg.annotation)
|
|
88
|
+
|
|
89
|
+
for node in ast.walk(tree):
|
|
90
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
91
|
+
mark_arg_annotations(node.args)
|
|
92
|
+
mark(node.returns)
|
|
93
|
+
elif isinstance(node, ast.AnnAssign):
|
|
94
|
+
mark(node.annotation)
|
|
95
|
+
return tree
|
|
96
|
+
|
|
97
|
+
|
|
52
98
|
class _DocstringRemover(ast.NodeTransformer):
|
|
53
99
|
"""移除 module/class/function 首部的 docstring"""
|
|
54
100
|
|
|
@@ -74,80 +120,156 @@ class _DocstringRemover(ast.NodeTransformer):
|
|
|
74
120
|
return self._strip_docstring(node)
|
|
75
121
|
|
|
76
122
|
|
|
77
|
-
|
|
78
|
-
"""
|
|
79
|
-
|
|
80
|
-
|
|
123
|
+
def _collect_names(nodes, ctx_type, *, skip_nested=True):
|
|
124
|
+
"""收集一组节点中的 Name;默认不穿透新的词法作用域。"""
|
|
125
|
+
names = set()
|
|
126
|
+
walker = _walk_no_nested_scope(nodes) if skip_nested else ast.walk(ast.Module(body=list(nodes), type_ignores=[]))
|
|
127
|
+
for child in walker:
|
|
128
|
+
if isinstance(child, ast.Name) and isinstance(child.ctx, ctx_type):
|
|
129
|
+
names.add(child.id)
|
|
130
|
+
return names
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _collect_argument_names(args):
|
|
134
|
+
"""收集函数/lambda 参数名。"""
|
|
135
|
+
names = set()
|
|
136
|
+
for arg in args.args + args.posonlyargs + args.kwonlyargs:
|
|
137
|
+
names.add(arg.arg)
|
|
138
|
+
if args.vararg:
|
|
139
|
+
names.add(args.vararg.arg)
|
|
140
|
+
if args.kwarg:
|
|
141
|
+
names.add(args.kwarg.arg)
|
|
142
|
+
return names
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _collect_argument_expression_nodes(args):
|
|
146
|
+
"""收集默认值与注解表达式,它们在外层作用域求值。"""
|
|
147
|
+
nodes = []
|
|
148
|
+
nodes.extend(args.defaults)
|
|
149
|
+
nodes.extend(default for default in args.kw_defaults if default is not None)
|
|
150
|
+
all_args = args.posonlyargs + args.args + args.kwonlyargs
|
|
151
|
+
if args.vararg:
|
|
152
|
+
all_args.append(args.vararg)
|
|
153
|
+
if args.kwarg:
|
|
154
|
+
all_args.append(args.kwarg)
|
|
155
|
+
for arg in all_args:
|
|
156
|
+
if arg.annotation is not None:
|
|
157
|
+
nodes.append(arg.annotation)
|
|
158
|
+
return nodes
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _collect_nonlocal_global_names(body):
|
|
162
|
+
"""收集当前作用域直接声明的 nonlocal/global 名称。"""
|
|
163
|
+
nonlocal_names = set()
|
|
164
|
+
global_names = set()
|
|
165
|
+
for child in _walk_no_nested_scope(body):
|
|
166
|
+
if isinstance(child, ast.Nonlocal):
|
|
167
|
+
nonlocal_names.update(child.names)
|
|
168
|
+
elif isinstance(child, ast.Global):
|
|
169
|
+
global_names.update(child.names)
|
|
170
|
+
return nonlocal_names, global_names
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _collect_direct_bound_names(body):
|
|
174
|
+
"""收集当前作用域直接绑定的名称,不穿透嵌套作用域。"""
|
|
175
|
+
bound = _collect_names(body, ast.Store)
|
|
176
|
+
for child in _walk_no_nested_scope(body):
|
|
177
|
+
if isinstance(child, ast.ExceptHandler) and child.name:
|
|
178
|
+
bound.add(child.name)
|
|
179
|
+
elif isinstance(child, (ast.Import, ast.ImportFrom)):
|
|
180
|
+
for alias in child.names:
|
|
181
|
+
bound.add(alias.asname or alias.name.split('.', 1)[0])
|
|
182
|
+
return bound
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _collect_load_names_no_nested(nodes):
|
|
186
|
+
"""收集 Load 名称,不穿透嵌套作用域。"""
|
|
187
|
+
return _collect_names(nodes, ast.Load)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _collect_nested_scope_nodes(body):
|
|
191
|
+
"""收集 body 中的直接/间接嵌套词法作用域节点。"""
|
|
192
|
+
nested = []
|
|
193
|
+
for node in body:
|
|
194
|
+
if isinstance(node, _SCOPE_BOUNDARY_NODES):
|
|
195
|
+
nested.append(node)
|
|
196
|
+
continue
|
|
197
|
+
for child in ast.iter_child_nodes(node):
|
|
198
|
+
if isinstance(child, _SCOPE_BOUNDARY_NODES):
|
|
199
|
+
nested.append(child)
|
|
200
|
+
else:
|
|
201
|
+
nested.extend(_collect_nested_scope_nodes([child]))
|
|
202
|
+
return nested
|
|
81
203
|
|
|
82
|
-
def __init__(self):
|
|
83
|
-
self._scope_stack = ['module']
|
|
84
204
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
205
|
+
def _collect_function_like_free_refs(node, local_names):
|
|
206
|
+
"""收集嵌套函数/lambda 中引用的外层变量名。"""
|
|
207
|
+
body = node.body if isinstance(node.body, list) else [node.body]
|
|
208
|
+
param_names = _collect_argument_names(node.args)
|
|
209
|
+
nonlocal_names, global_names = _collect_nonlocal_global_names(body)
|
|
210
|
+
nested_locals = _collect_direct_bound_names(body)
|
|
211
|
+
nested_locals.update(param_names)
|
|
212
|
+
nested_locals -= nonlocal_names
|
|
90
213
|
|
|
91
|
-
|
|
214
|
+
free = set()
|
|
215
|
+
outer_expr_nodes = _collect_argument_expression_nodes(node.args)
|
|
216
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
217
|
+
outer_expr_nodes.extend(node.decorator_list)
|
|
218
|
+
if node.returns is not None:
|
|
219
|
+
outer_expr_nodes.append(node.returns)
|
|
220
|
+
free.update(_collect_load_names_no_nested(outer_expr_nodes) & local_names)
|
|
221
|
+
|
|
222
|
+
for name in _collect_load_names_no_nested(body):
|
|
223
|
+
if name in local_names and name not in nested_locals and name not in global_names:
|
|
224
|
+
free.add(name)
|
|
225
|
+
|
|
226
|
+
# ``nonlocal`` 声明的变量即使只被 Store(如 current_tokens = 0)使用,
|
|
227
|
+
# 也必须视为外层闭包引用。若外层变量被重命名而 nonlocal 声明仍保留原名,
|
|
228
|
+
# Cython 会在编译期报 ``no binding for nonlocal ... found``。
|
|
229
|
+
free.update(nonlocal_names & local_names)
|
|
230
|
+
|
|
231
|
+
free.update(_collect_nested_free_refs(body, local_names))
|
|
232
|
+
return free
|
|
92
233
|
|
|
93
|
-
def visit_ClassDef(self, node):
|
|
94
|
-
self._scope_stack.append('class')
|
|
95
|
-
self.generic_visit(node)
|
|
96
|
-
self._scope_stack.pop()
|
|
97
|
-
if not node.body:
|
|
98
|
-
node.body.append(ast.Pass())
|
|
99
|
-
return node
|
|
100
234
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
235
|
+
def _collect_class_free_refs(node, local_names):
|
|
236
|
+
"""收集嵌套类体中直接引用的外层变量名。"""
|
|
237
|
+
free = set()
|
|
238
|
+
outer_expr_nodes = list(node.decorator_list)
|
|
239
|
+
outer_expr_nodes.extend(node.bases)
|
|
240
|
+
outer_expr_nodes.extend(keyword.value for keyword in node.keywords)
|
|
241
|
+
free.update(_collect_load_names_no_nested(outer_expr_nodes) & local_names)
|
|
242
|
+
|
|
243
|
+
for name in _collect_load_names_no_nested(node.body):
|
|
244
|
+
if name in local_names:
|
|
245
|
+
free.add(name)
|
|
246
|
+
free.update(_collect_nested_free_refs(node.body, local_names))
|
|
247
|
+
return free
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _collect_comprehension_free_refs(node, local_names):
|
|
251
|
+
"""保守收集 comprehension 中对外层变量的引用。
|
|
252
|
+
|
|
253
|
+
comprehension 是隐式函数作用域;为避免 Cython/CPython 闭包细节差异,
|
|
254
|
+
只要其中出现外层局部名,就将该外层名排除出重命名集合。
|
|
255
|
+
"""
|
|
256
|
+
free = set()
|
|
257
|
+
for child in ast.walk(node):
|
|
258
|
+
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load) and child.id in local_names:
|
|
259
|
+
free.add(child.id)
|
|
260
|
+
return free
|
|
110
261
|
|
|
111
262
|
|
|
112
263
|
def _collect_nested_free_refs(body, local_names):
|
|
113
|
-
"""
|
|
264
|
+
"""收集嵌套词法作用域中引用的外层变量名(闭包变量)"""
|
|
114
265
|
free = set()
|
|
115
|
-
for node in body:
|
|
116
|
-
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
117
|
-
|
|
118
|
-
nested_locals = set()
|
|
119
|
-
# nonlocal/global 声明的变量不是局部变量
|
|
120
|
-
nonlocal_names = set()
|
|
121
|
-
for child in _walk_no_nested_scope(node.body):
|
|
122
|
-
if isinstance(child, (ast.Nonlocal, ast.Global)):
|
|
123
|
-
nonlocal_names.update(child.names)
|
|
124
|
-
for arg in node.args.args + node.args.posonlyargs + node.args.kwonlyargs:
|
|
125
|
-
nested_locals.add(arg.arg)
|
|
126
|
-
if node.args.vararg:
|
|
127
|
-
nested_locals.add(node.args.vararg.arg)
|
|
128
|
-
if node.args.kwarg:
|
|
129
|
-
nested_locals.add(node.args.kwarg.arg)
|
|
130
|
-
for child in _walk_no_nested_scope(node.body):
|
|
131
|
-
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Store):
|
|
132
|
-
if child.id not in nonlocal_names:
|
|
133
|
-
nested_locals.add(child.id)
|
|
134
|
-
# 嵌套函数中读取的、属于外层 local_names 且不被自身遮蔽的名字
|
|
135
|
-
for child in ast.walk(node):
|
|
136
|
-
if isinstance(child, ast.Name) and child.id in local_names and child.id not in nested_locals:
|
|
137
|
-
free.add(child.id)
|
|
266
|
+
for node in _collect_nested_scope_nodes(body):
|
|
267
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)):
|
|
268
|
+
free.update(_collect_function_like_free_refs(node, local_names))
|
|
138
269
|
elif isinstance(node, ast.ClassDef):
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
free.add(child.id)
|
|
143
|
-
free |= _collect_nested_free_refs(node.body, local_names)
|
|
144
|
-
else:
|
|
145
|
-
# 递归搜索所有子节点中的嵌套函数/类(穿透 Try/With/For/If 等)
|
|
146
|
-
for child in ast.walk(node):
|
|
147
|
-
if child is node:
|
|
148
|
-
continue
|
|
149
|
-
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
|
150
|
-
free |= _collect_nested_free_refs([child], local_names)
|
|
270
|
+
free.update(_collect_class_free_refs(node, local_names))
|
|
271
|
+
elif isinstance(node, (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)):
|
|
272
|
+
free.update(_collect_comprehension_free_refs(node, local_names))
|
|
151
273
|
return free
|
|
152
274
|
|
|
153
275
|
|
|
@@ -167,26 +289,20 @@ class _LocalVarRenamer(ast.NodeTransformer):
|
|
|
167
289
|
|
|
168
290
|
# 收集参数名(不重命名)
|
|
169
291
|
param_names = set()
|
|
170
|
-
|
|
171
|
-
param_names.add(arg.arg)
|
|
172
|
-
if node.args.vararg:
|
|
173
|
-
param_names.add(node.args.vararg.arg)
|
|
174
|
-
if node.args.kwarg:
|
|
175
|
-
param_names.add(node.args.kwarg.arg)
|
|
292
|
+
param_names.update(_collect_argument_names(node.args))
|
|
176
293
|
|
|
177
294
|
# 收集局部赋值目标(不穿透嵌套作用域)
|
|
178
295
|
local_names = set()
|
|
179
296
|
# 排除 nonlocal/global 声明的变量
|
|
180
|
-
nonlocal_names =
|
|
297
|
+
nonlocal_names, global_names = _collect_nonlocal_global_names(node.body)
|
|
298
|
+
excluded_scope_names = nonlocal_names | global_names
|
|
181
299
|
for child in _walk_no_nested_scope(node.body):
|
|
182
|
-
if isinstance(child, (ast.Nonlocal, ast.Global)):
|
|
183
|
-
nonlocal_names.update(child.names)
|
|
184
300
|
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Store):
|
|
185
301
|
name = child.id
|
|
186
|
-
if (name not in param_names and name
|
|
302
|
+
if (name not in param_names and name not in excluded_scope_names
|
|
303
|
+
and name != 'self' and name != 'cls'
|
|
187
304
|
and not name.startswith('__')):
|
|
188
305
|
local_names.add(name)
|
|
189
|
-
local_names -= nonlocal_names
|
|
190
306
|
|
|
191
307
|
if not local_names:
|
|
192
308
|
self.generic_visit(node)
|
|
@@ -484,6 +600,7 @@ class _OpaquePredicateInserter(ast.NodeTransformer):
|
|
|
484
600
|
def obfuscate_source(source_code: str, seed=None) -> str:
|
|
485
601
|
"""对源码执行六重 AST 变换:去 docstring、局部变量重命名、
|
|
486
602
|
字符串加密、常量折叠、控制流平坦化、虚假分支。
|
|
603
|
+
函数、类和局部变量 annotation 默认保留。
|
|
487
604
|
ast.unparse() 天然丢弃所有注释。
|
|
488
605
|
|
|
489
606
|
:param seed: 随机种子;传入后可复现混淆结果
|
|
@@ -496,6 +613,7 @@ def obfuscate_source(source_code: str, seed=None) -> str:
|
|
|
496
613
|
tree = _LocalVarRenamer().visit(tree)
|
|
497
614
|
tree = _ControlFlowFlattener(rng=rng).visit(tree)
|
|
498
615
|
tree = _OpaquePredicateInserter(rng=rng).visit(tree)
|
|
616
|
+
tree = _mark_annotation_constants(tree)
|
|
499
617
|
tree = _StringEncryptor(rng=rng).visit(tree)
|
|
500
618
|
tree = _ConstantFoldingObfuscator(rng=rng).visit(tree)
|
|
501
619
|
ast.fix_missing_locations(tree)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AutoCython-zhang
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.8
|
|
4
4
|
Summary: 自动Cython,使用Cython批量编译.py文件为.pyd文件!
|
|
5
5
|
Author-email: zhang_gavin <qq814608@163.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -20,7 +20,7 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
# AutoCython
|
|
22
22
|
|
|
23
|
-
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd
|
|
23
|
+
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd`),支持六重 AST 混淆、并发编译、跨平台运行。
|
|
24
24
|
|
|
25
25
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
26
26
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
@@ -33,7 +33,7 @@ AutoCython 是一个 Python 源码保护工具,通过 Cython 编译 + AST 混
|
|
|
33
33
|
## 特性
|
|
34
34
|
|
|
35
35
|
- **一键编译** — 单文件 (`-f`) 或整目录 (`-p`) 批量编译为 `.so`/`.pyd`
|
|
36
|
-
-
|
|
36
|
+
- **六重 AST 混淆** — docstring 移除、局部变量重命名、字符串 XOR 加密、常量折叠、控制流平坦化、虚假分支注入;默认完整保留运行时 annotation,兼容 FastAPI / Pydantic / dataclass
|
|
37
37
|
- **并发编译** — 基于 `ThreadPoolExecutor` 的多线程并行编译,可配置并发数
|
|
38
38
|
- **实时进度面板** — 基于 Rich 的实时任务状态表格、进度条、耗时统计
|
|
39
39
|
- **跨平台** — 支持 Linux、macOS、Windows,自动适配 `.so`/`.pyd` 扩展名
|
|
@@ -50,6 +50,8 @@ pip install AutoCython-zhang
|
|
|
50
50
|
|
|
51
51
|
> 当前编译链要求 `Cython>=3,<4`。该约束用于避免旧版 Cython 在编译后破坏 `Pydantic` / `FastAPI` / `dataclass` 等依赖运行时注解的框架行为。
|
|
52
52
|
|
|
53
|
+
> v2.3.8 修复了 `nonlocal` 闭包变量在混淆重命名后无法被 Cython 绑定的问题,适用于包含内层 flush/helper 函数的项目构建。
|
|
54
|
+
|
|
53
55
|
### 依赖
|
|
54
56
|
|
|
55
57
|
| 包 | 用途 |
|
|
@@ -108,7 +110,7 @@ print(f"生成: {output}")
|
|
|
108
110
|
|------|------|------|
|
|
109
111
|
| `compile()` | `AutoCython.AutoCython` | 主入口:解析参数并调度编译任务 |
|
|
110
112
|
| `compile_to_binary()` | `AutoCython.compile` | 将单个 `.py` 文件编译为二进制扩展 |
|
|
111
|
-
| `obfuscate_source()` | `AutoCython.obfuscate` |
|
|
113
|
+
| `obfuscate_source()` | `AutoCython.obfuscate` | 对源码执行六重 AST 混淆变换,并保留运行时 annotation |
|
|
112
114
|
| `run_tasks()` | `AutoCython.run_tasks` | 并发任务执行引擎(含实时进度面板) |
|
|
113
115
|
| `find_python_files()` | `AutoCython.tools` | 递归扫描目录下的可编译 `.py` 文件 |
|
|
114
116
|
| `parse_arguments()` | `AutoCython.tools` | CLI 参数解析(中英双语) |
|
|
@@ -124,7 +126,7 @@ AutoCython/
|
|
|
124
126
|
│ ├── _version.py # 单一版本号来源
|
|
125
127
|
│ ├── AutoCython.py # 主编译调度逻辑
|
|
126
128
|
│ ├── compile.py # Cython 编译核心(临时目录隔离)
|
|
127
|
-
│ ├── obfuscate.py #
|
|
129
|
+
│ ├── obfuscate.py # 六重 AST 混淆引擎
|
|
128
130
|
│ ├── run_tasks.py # 并发任务执行 + Rich 实时面板
|
|
129
131
|
│ └── tools.py # CLI 参数解析、文件扫描、国际化
|
|
130
132
|
├── tests/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AutoCython-zhang
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.8
|
|
4
4
|
Summary: 自动Cython,使用Cython批量编译.py文件为.pyd文件!
|
|
5
5
|
Author-email: zhang_gavin <qq814608@163.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -20,7 +20,7 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
# AutoCython
|
|
22
22
|
|
|
23
|
-
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd
|
|
23
|
+
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd`),支持六重 AST 混淆、并发编译、跨平台运行。
|
|
24
24
|
|
|
25
25
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
26
26
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
@@ -33,7 +33,7 @@ AutoCython 是一个 Python 源码保护工具,通过 Cython 编译 + AST 混
|
|
|
33
33
|
## 特性
|
|
34
34
|
|
|
35
35
|
- **一键编译** — 单文件 (`-f`) 或整目录 (`-p`) 批量编译为 `.so`/`.pyd`
|
|
36
|
-
-
|
|
36
|
+
- **六重 AST 混淆** — docstring 移除、局部变量重命名、字符串 XOR 加密、常量折叠、控制流平坦化、虚假分支注入;默认完整保留运行时 annotation,兼容 FastAPI / Pydantic / dataclass
|
|
37
37
|
- **并发编译** — 基于 `ThreadPoolExecutor` 的多线程并行编译,可配置并发数
|
|
38
38
|
- **实时进度面板** — 基于 Rich 的实时任务状态表格、进度条、耗时统计
|
|
39
39
|
- **跨平台** — 支持 Linux、macOS、Windows,自动适配 `.so`/`.pyd` 扩展名
|
|
@@ -50,6 +50,8 @@ pip install AutoCython-zhang
|
|
|
50
50
|
|
|
51
51
|
> 当前编译链要求 `Cython>=3,<4`。该约束用于避免旧版 Cython 在编译后破坏 `Pydantic` / `FastAPI` / `dataclass` 等依赖运行时注解的框架行为。
|
|
52
52
|
|
|
53
|
+
> v2.3.8 修复了 `nonlocal` 闭包变量在混淆重命名后无法被 Cython 绑定的问题,适用于包含内层 flush/helper 函数的项目构建。
|
|
54
|
+
|
|
53
55
|
### 依赖
|
|
54
56
|
|
|
55
57
|
| 包 | 用途 |
|
|
@@ -108,7 +110,7 @@ print(f"生成: {output}")
|
|
|
108
110
|
|------|------|------|
|
|
109
111
|
| `compile()` | `AutoCython.AutoCython` | 主入口:解析参数并调度编译任务 |
|
|
110
112
|
| `compile_to_binary()` | `AutoCython.compile` | 将单个 `.py` 文件编译为二进制扩展 |
|
|
111
|
-
| `obfuscate_source()` | `AutoCython.obfuscate` |
|
|
113
|
+
| `obfuscate_source()` | `AutoCython.obfuscate` | 对源码执行六重 AST 混淆变换,并保留运行时 annotation |
|
|
112
114
|
| `run_tasks()` | `AutoCython.run_tasks` | 并发任务执行引擎(含实时进度面板) |
|
|
113
115
|
| `find_python_files()` | `AutoCython.tools` | 递归扫描目录下的可编译 `.py` 文件 |
|
|
114
116
|
| `parse_arguments()` | `AutoCython.tools` | CLI 参数解析(中英双语) |
|
|
@@ -124,7 +126,7 @@ AutoCython/
|
|
|
124
126
|
│ ├── _version.py # 单一版本号来源
|
|
125
127
|
│ ├── AutoCython.py # 主编译调度逻辑
|
|
126
128
|
│ ├── compile.py # Cython 编译核心(临时目录隔离)
|
|
127
|
-
│ ├── obfuscate.py #
|
|
129
|
+
│ ├── obfuscate.py # 六重 AST 混淆引擎
|
|
128
130
|
│ ├── run_tasks.py # 并发任务执行 + Rich 实时面板
|
|
129
131
|
│ └── tools.py # CLI 参数解析、文件扫描、国际化
|
|
130
132
|
├── tests/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AutoCython
|
|
2
2
|
|
|
3
|
-
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd
|
|
3
|
+
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd`),支持六重 AST 混淆、并发编译、跨平台运行。
|
|
4
4
|
|
|
5
5
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
6
6
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
@@ -13,7 +13,7 @@ AutoCython 是一个 Python 源码保护工具,通过 Cython 编译 + AST 混
|
|
|
13
13
|
## 特性
|
|
14
14
|
|
|
15
15
|
- **一键编译** — 单文件 (`-f`) 或整目录 (`-p`) 批量编译为 `.so`/`.pyd`
|
|
16
|
-
-
|
|
16
|
+
- **六重 AST 混淆** — docstring 移除、局部变量重命名、字符串 XOR 加密、常量折叠、控制流平坦化、虚假分支注入;默认完整保留运行时 annotation,兼容 FastAPI / Pydantic / dataclass
|
|
17
17
|
- **并发编译** — 基于 `ThreadPoolExecutor` 的多线程并行编译,可配置并发数
|
|
18
18
|
- **实时进度面板** — 基于 Rich 的实时任务状态表格、进度条、耗时统计
|
|
19
19
|
- **跨平台** — 支持 Linux、macOS、Windows,自动适配 `.so`/`.pyd` 扩展名
|
|
@@ -30,6 +30,8 @@ pip install AutoCython-zhang
|
|
|
30
30
|
|
|
31
31
|
> 当前编译链要求 `Cython>=3,<4`。该约束用于避免旧版 Cython 在编译后破坏 `Pydantic` / `FastAPI` / `dataclass` 等依赖运行时注解的框架行为。
|
|
32
32
|
|
|
33
|
+
> v2.3.8 修复了 `nonlocal` 闭包变量在混淆重命名后无法被 Cython 绑定的问题,适用于包含内层 flush/helper 函数的项目构建。
|
|
34
|
+
|
|
33
35
|
### 依赖
|
|
34
36
|
|
|
35
37
|
| 包 | 用途 |
|
|
@@ -88,7 +90,7 @@ print(f"生成: {output}")
|
|
|
88
90
|
|------|------|------|
|
|
89
91
|
| `compile()` | `AutoCython.AutoCython` | 主入口:解析参数并调度编译任务 |
|
|
90
92
|
| `compile_to_binary()` | `AutoCython.compile` | 将单个 `.py` 文件编译为二进制扩展 |
|
|
91
|
-
| `obfuscate_source()` | `AutoCython.obfuscate` |
|
|
93
|
+
| `obfuscate_source()` | `AutoCython.obfuscate` | 对源码执行六重 AST 混淆变换,并保留运行时 annotation |
|
|
92
94
|
| `run_tasks()` | `AutoCython.run_tasks` | 并发任务执行引擎(含实时进度面板) |
|
|
93
95
|
| `find_python_files()` | `AutoCython.tools` | 递归扫描目录下的可编译 `.py` 文件 |
|
|
94
96
|
| `parse_arguments()` | `AutoCython.tools` | CLI 参数解析(中英双语) |
|
|
@@ -104,7 +106,7 @@ AutoCython/
|
|
|
104
106
|
│ ├── _version.py # 单一版本号来源
|
|
105
107
|
│ ├── AutoCython.py # 主编译调度逻辑
|
|
106
108
|
│ ├── compile.py # Cython 编译核心(临时目录隔离)
|
|
107
|
-
│ ├── obfuscate.py #
|
|
109
|
+
│ ├── obfuscate.py # 六重 AST 混淆引擎
|
|
108
110
|
│ ├── run_tasks.py # 并发任务执行 + Rich 实时面板
|
|
109
111
|
│ └── tools.py # CLI 参数解析、文件扫描、国际化
|
|
110
112
|
├── tests/
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{autocython_zhang-2.3.6 → autocython_zhang-2.3.8}/AutoCython_zhang.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|