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