a4943a56 by 周伟奇

py2so

0 parents
1 build*
2 .idea
...\ No newline at end of file ...\ No newline at end of file
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 ```
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()
1 from pkg import SC
2 from tools.test_func import test_func
3
4 sc = SC()
5 test_func()
1 from .test_class import SuperClass as SC
No preview for this file type
No preview for this file type
1 class SuperClass:
2
3 def __init__(self):
4 print('super class')
File mode changed
1 def test_func():
2 print('test func')
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!