-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpyfm.py
More file actions
115 lines (89 loc) · 3.14 KB
/
pyfm.py
File metadata and controls
115 lines (89 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import argparse
import sys
from datetime import datetime
from typing import List, Set, Tuple
HEADER = \
"# THIS FILE IS GENERATED BY python-file-merger (https://github.com/weyh/python-file-merger).\n" + \
"# DO NOT EDIT IT DIRECTLY!\n" + \
f"# DATE: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
class File:
shebang: str
file_path: str
imports: List[str]
prog_lines: List[str]
@staticmethod
def __parse_file(path: str) -> Tuple[str, List[str], List[str]]:
shebang = ""
imports: List[str] = []
prog_lines: List[str] = []
with open(path, "r") as f:
for line in f:
if line.startswith("#!"):
shebang = line
elif line.startswith("import") or line.startswith("from"):
# move all imports to the top
imports.append(line.strip())
else:
prog_lines.append(line)
return (shebang, imports, prog_lines)
def __init__(self, file_path: str):
if not file_path.endswith(".py"):
raise Exception("File must be a python file")
self.file_path = file_path.replace("\\", "/")
self.shebang, self.imports, self.prog_lines = File.__parse_file(file_path)
def get_file_name(self) -> str:
return self.file_path.split("/")[-1].replace(".py", "")
def create_output_file(file_path: str, files: List[File]):
shebang = ""
inline_import: List[str] = []
imports: Set[str] = set()
lines: List[str] = []
# get shebang
for file in files:
if file.shebang != "":
if shebang != "":
raise Exception("Multiple shebangs found")
else:
shebang = file.shebang
# get imports
for file in files:
for imp in file.imports:
if any([file.get_file_name() in imp for file in files]):
if imp.startswith("import"):
inline_import.append(file.get_file_name())
else:
imports.add(imp)
# get program lines
for file in files:
lines.append(f"\n# {file.file_path}\n")
for line in file.prog_lines:
found = False
for ii in inline_import:
if f"{ii}." in line:
lines.append(line.replace(f"{ii}.", ""))
found = True
if not found:
lines.append(line)
with open(file_path, "w") as f:
if shebang != "":
f.write(f"{shebang}\n")
f.write(f"\n{HEADER}\n")
f.writelines([f"{i}\n" for i in imports])
f.writelines(lines)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("files", nargs="+", help="Files to merge")
parser.add_argument("-o", "--output", help="Output file")
return parser.parse_args()
def main() -> int:
ret = 0
pargs = parse_args()
try:
files = [File(path) for path in pargs.files]
create_output_file(pargs.output, files)
except Exception as e:
print(e)
ret = 1
return ret
if __name__ == '__main__':
sys.exit(main())