py2so
0 parents
Showing
11 changed files
with
170 additions
and
0 deletions
.gitignore
0 → 100644
README.md
0 → 100644
1 | ## 保护源码:py2so.py | ||
2 | - help text | ||
3 | ``` | ||
4 | ❯ python py2so.py -h | ||
5 | usage: py2so.py [-h] -i INPUT [-o OUTPUT] [-e EXCLUDE] | ||
6 | |||
7 | compile the .py to .so(Linux/Mac) or .pdy(Win) | ||
8 | |||
9 | optional arguments: | ||
10 | -h, --help show this help message and exit | ||
11 | -i INPUT, --input INPUT | ||
12 | the directory(file) path of your project | ||
13 | -o OUTPUT, --output OUTPUT | ||
14 | the directory path of compiled file | ||
15 | -e EXCLUDE, --exclude EXCLUDE | ||
16 | exclude file. eg: ignore/ignore.py,main.py,ignore | ||
17 | ``` | ||
18 | - example | ||
19 | ``` | ||
20 | python py2so.py -i test -e test,main.py | ||
21 | ``` |
py2so.py
0 → 100644
1 | import os | ||
2 | import sys | ||
3 | import time | ||
4 | import shutil | ||
5 | import argparse | ||
6 | from distutils.core import setup | ||
7 | from distutils.extension import Extension | ||
8 | from Cython.Build import cythonize | ||
9 | from Cython.Distutils import build_ext | ||
10 | |||
11 | |||
12 | if sys.version_info[0] < 3: | ||
13 | raise Exception("This program requires at least python3.6") | ||
14 | |||
15 | |||
16 | parser = argparse.ArgumentParser(description='compile the .py to .so(Linux/Mac) or .pdy(Win)') | ||
17 | parser.add_argument('-i', '--input', help='the directory(file) path of your project', required=True) | ||
18 | parser.add_argument('-o', '--output', help='the directory path of compiled file') | ||
19 | parser.add_argument('-e', '--exclude', help='exclude file. eg: ignore/ignore.py,main.py,ignore') | ||
20 | args = parser.parse_args() | ||
21 | |||
22 | |||
23 | def get_exclude_paths(input_path): | ||
24 | exclude_paths = [] | ||
25 | if args.exclude is not None and os.path.isdir(input_path): | ||
26 | paths = args.exclude.split(',') | ||
27 | for path in paths: | ||
28 | abs_path = path if os.path.isabs(path) else os.path.join(input_path, path) | ||
29 | if not os.path.exists(abs_path): | ||
30 | print('Warning: exclude path not exists: {0}'.format(abs_path)) | ||
31 | continue | ||
32 | exclude_paths.append(abs_path) | ||
33 | return set(exclude_paths) | ||
34 | |||
35 | |||
36 | def get_py_files(dir_path, exclude_paths): | ||
37 | for parent, _, filenames in os.walk(dir_path): | ||
38 | if parent in exclude_paths: | ||
39 | print('exclude path: {0}'.format(parent)) | ||
40 | continue | ||
41 | for filename in filenames: | ||
42 | if not filename.endswith('.py'): | ||
43 | continue | ||
44 | file_path = os.path.join(parent, filename) | ||
45 | if file_path in exclude_paths: | ||
46 | print('exclude path: {0}'.format(file_path)) | ||
47 | continue | ||
48 | yield file_path | ||
49 | |||
50 | |||
51 | def del_c(dir_path, timestamp): | ||
52 | if not os.path.isdir(dir_path): | ||
53 | c_file_path = '{0}.c'.format(os.path.splitext(dir_path)[0]) | ||
54 | os.remove(c_file_path) | ||
55 | print('remove c file path: {0}'.format(c_file_path)) | ||
56 | return | ||
57 | for parent, _, filenames in os.walk(dir_path): | ||
58 | for filename in filenames: | ||
59 | file_path = os.path.join(parent, filename) | ||
60 | if filename.endswith('.c') and os.stat(file_path).st_mtime > timestamp: | ||
61 | os.remove(file_path) | ||
62 | print('remove c file path: {0}'.format(file_path)) | ||
63 | |||
64 | |||
65 | def get_extensions(file_paths, input_path): | ||
66 | print('---------- python file summary ----------') | ||
67 | extensions = [] | ||
68 | for file_path in file_paths: | ||
69 | if os.path.isfile(input_path): | ||
70 | relpath = os.path.basename(file_path) | ||
71 | else: | ||
72 | relpath = os.path.relpath(file_path, start=input_path) | ||
73 | name = os.path.splitext(relpath)[0].replace(os.path.sep, '.') | ||
74 | sources = [file_path] | ||
75 | print('python file path: {0} module name: {1}'.format(file_path, name)) | ||
76 | extension = Extension(name, sources) | ||
77 | extension.cython_c_in_temp = True | ||
78 | extensions.append(extension) | ||
79 | return extensions | ||
80 | |||
81 | |||
82 | def main(): | ||
83 | input_path = os.path.realpath(args.input) | ||
84 | if not os.path.exists(input_path): | ||
85 | print('input path not exists: {0}'.format(input_path)) | ||
86 | return | ||
87 | |||
88 | timestamp = int(time.time()) | ||
89 | build_dir_name = 'build_{0}'.format(timestamp) | ||
90 | tmp_dir_name = 'tmp_{0}'.format(timestamp) | ||
91 | if args.output is None: | ||
92 | output_path = os.path.join(os.path.dirname(input_path), build_dir_name) | ||
93 | else: | ||
94 | output_path = os.path.realpath(args.output) | ||
95 | tmp_path = os.path.join(output_path, tmp_dir_name) | ||
96 | os.makedirs(tmp_path, exist_ok=True) | ||
97 | |||
98 | exclude_paths = get_exclude_paths(input_path) | ||
99 | |||
100 | if os.path.isdir(input_path): | ||
101 | file_paths = get_py_files(input_path, exclude_paths) | ||
102 | else: | ||
103 | file_paths = [input_path] | ||
104 | |||
105 | print('---------- directory summary ----------') | ||
106 | print('input path: {0}'.format(input_path)) | ||
107 | print('output path: {0}'.format(output_path)) | ||
108 | print('output tmp path: {0}'.format(tmp_path)) | ||
109 | print('exclude paths: {0}'.format(exclude_paths)) | ||
110 | extensions = get_extensions(file_paths, input_path) | ||
111 | |||
112 | print('---------- compile start ----------') | ||
113 | try: | ||
114 | compiler_directives = {"language_level": '3'} | ||
115 | ext_modules = cythonize(module_list=extensions, | ||
116 | compiler_directives=compiler_directives) | ||
117 | |||
118 | setup(cmdclass={'build_ext': build_ext}, | ||
119 | ext_modules=ext_modules, script_args=["build_ext", "-b", output_path, "-t", tmp_path]) | ||
120 | except Extension as e: | ||
121 | print('---------- compile failed ----------') | ||
122 | print('compile error: {0}'.format(e)) | ||
123 | else: | ||
124 | print('---------- compile completed ----------') | ||
125 | print('output path: {0}'.format(output_path)) | ||
126 | finally: | ||
127 | print('---------- cleaning ----------') | ||
128 | if os.path.exists(tmp_path): | ||
129 | shutil.rmtree(tmp_path) | ||
130 | print('remove output tmp path: {0}'.format(tmp_path)) | ||
131 | del_c(input_path, timestamp) | ||
132 | |||
133 | |||
134 | if __name__ == '__main__': | ||
135 | main() |
test/main.py
0 → 100644
test/pkg/__init__.py
0 → 100644
1 | from .test_class import SuperClass as SC |
test/pkg/__pycache__/__init__.cpython-36.pyc
0 → 100644
No preview for this file type
No preview for this file type
test/pkg/test_class.py
0 → 100644
test/test/test.py
0 → 100644
File mode changed
No preview for this file type
test/tools/test_func.py
0 → 100644
-
Please register or sign in to post a comment