mseep-patche 1.0.1__py3-none-any.whl
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.
- Patche/__init__.py +1 -0
- Patche/__main__.py +3 -0
- Patche/__version__.py +9 -0
- Patche/app.py +32 -0
- Patche/commands/apply.py +107 -0
- Patche/commands/help.py +12 -0
- Patche/commands/show.py +41 -0
- Patche/config.py +24 -0
- Patche/mcp/__init__.py +42 -0
- Patche/mcp/__main__.py +3 -0
- Patche/mcp/model.py +29 -0
- Patche/mcp/prompts.py +313 -0
- Patche/mcp/server.py +101 -0
- Patche/mcp/tools.py +160 -0
- Patche/model.py +75 -0
- Patche/utils/common.py +73 -0
- Patche/utils/header.py +34 -0
- Patche/utils/parse.py +269 -0
- Patche/utils/resolve.py +168 -0
- mseep_patche-1.0.1.dist-info/METADATA +14 -0
- mseep_patche-1.0.1.dist-info/RECORD +24 -0
- mseep_patche-1.0.1.dist-info/WHEEL +4 -0
- mseep_patche-1.0.1.dist-info/entry_points.txt +6 -0
- mseep_patche-1.0.1.dist-info/licenses/LICENSE +21 -0
Patche/utils/parse.py
ADDED
@@ -0,0 +1,269 @@
|
|
1
|
+
import re
|
2
|
+
from typing import List, Optional
|
3
|
+
|
4
|
+
from whatthepatch_pydantic import parse_patch as wtp_parse_patch
|
5
|
+
from whatthepatch_pydantic.model import Diff as WTPDiff
|
6
|
+
|
7
|
+
from Patche.config import settings
|
8
|
+
from Patche.model import Change, Diff, Hunk, Patch
|
9
|
+
from Patche.utils.header import CHANGE_LINE, HEADER_OLD, HUNK_START, parse_header
|
10
|
+
|
11
|
+
git_diffcmd_header = re.compile("^diff --git a/(.+) b/(.+)$")
|
12
|
+
unified_diff_header = re.compile("^---\s{1}")
|
13
|
+
spliter_line = re.compile("^---$")
|
14
|
+
|
15
|
+
|
16
|
+
def changes_to_hunks(changes: list[Change]) -> list[Hunk]:
|
17
|
+
"""
|
18
|
+
Convert a list of changes to a list of hunks
|
19
|
+
|
20
|
+
Args:
|
21
|
+
changes (list[Change]): A list of changes
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
list[Hunk]: A list of hunks
|
25
|
+
"""
|
26
|
+
|
27
|
+
# 首先统计 Hunk 数
|
28
|
+
hunk_indexes = []
|
29
|
+
for change in changes:
|
30
|
+
if change.hunk not in hunk_indexes:
|
31
|
+
hunk_indexes.append(change.hunk)
|
32
|
+
|
33
|
+
# 将changes按照hunk分组,注意同一个 hunk 中的 change 要进行分类,前三行要放入前置上下文,中间的要放入中间上下文,后三行要放入后置上下文
|
34
|
+
hunk_list: list[Hunk] = []
|
35
|
+
for hunk_index in hunk_indexes:
|
36
|
+
hunk_changes = [change for change in changes if change.hunk == hunk_index]
|
37
|
+
|
38
|
+
# 这里遍历的顺序已经是正确的顺序
|
39
|
+
hunk_context = []
|
40
|
+
hunk_middle = []
|
41
|
+
hunk_post = []
|
42
|
+
# 首先正向遍历,获取前置上下文
|
43
|
+
for change in hunk_changes:
|
44
|
+
if change.old is not None and change.new is not None:
|
45
|
+
hunk_context.append(change)
|
46
|
+
else:
|
47
|
+
break
|
48
|
+
|
49
|
+
# 然后反向遍历,获取后置上下文
|
50
|
+
for change in reversed(hunk_changes):
|
51
|
+
if change.old is not None and change.new is not None:
|
52
|
+
hunk_post.append(change)
|
53
|
+
else:
|
54
|
+
break
|
55
|
+
|
56
|
+
assert len(hunk_context) <= settings.max_diff_lines
|
57
|
+
assert len(hunk_post) <= settings.max_diff_lines
|
58
|
+
|
59
|
+
# 最后获取中间代码
|
60
|
+
for change in hunk_changes:
|
61
|
+
if change not in hunk_context and change not in hunk_post:
|
62
|
+
hunk_middle.append(change)
|
63
|
+
|
64
|
+
# 注意把后置上下文反转回来
|
65
|
+
hunk_post = list(reversed(hunk_post))
|
66
|
+
|
67
|
+
hunk_list.append(
|
68
|
+
Hunk(
|
69
|
+
index=hunk_index,
|
70
|
+
context=hunk_context,
|
71
|
+
middle=hunk_middle,
|
72
|
+
post=hunk_post,
|
73
|
+
all_=hunk_changes,
|
74
|
+
)
|
75
|
+
)
|
76
|
+
|
77
|
+
return hunk_list
|
78
|
+
|
79
|
+
|
80
|
+
def wtp_diff_to_diff(wtp_diff: WTPDiff) -> Diff:
|
81
|
+
"""
|
82
|
+
Convert a whatthepatch Diff object to a patche Diff object
|
83
|
+
|
84
|
+
Args:
|
85
|
+
wtp_diff (WTPDiff): A whatthepatch Diff object
|
86
|
+
|
87
|
+
Returns:
|
88
|
+
Diff: A patche Diff object
|
89
|
+
"""
|
90
|
+
|
91
|
+
return Diff(
|
92
|
+
header=wtp_diff.header,
|
93
|
+
changes=wtp_diff.changes,
|
94
|
+
text=wtp_diff.text,
|
95
|
+
hunks=changes_to_hunks(wtp_diff.changes),
|
96
|
+
)
|
97
|
+
|
98
|
+
|
99
|
+
def parse_unified_diff(text: str) -> Optional[List[Diff]]:
|
100
|
+
"""解析 unified diff 格式的补丁"""
|
101
|
+
lines = iter(text.splitlines())
|
102
|
+
diffs: List[Diff] = []
|
103
|
+
|
104
|
+
while True:
|
105
|
+
try:
|
106
|
+
header = parse_header(lines)
|
107
|
+
if not header:
|
108
|
+
break
|
109
|
+
|
110
|
+
changes: List[Change] = []
|
111
|
+
hunk_index = 0
|
112
|
+
|
113
|
+
for line in lines:
|
114
|
+
# 检查是否是新的 diff 块开始
|
115
|
+
if HEADER_OLD.match(line):
|
116
|
+
lines = iter([line] + list(lines))
|
117
|
+
break
|
118
|
+
|
119
|
+
# 解析 hunk 头
|
120
|
+
hunk_match = HUNK_START.match(line)
|
121
|
+
if hunk_match:
|
122
|
+
old_start = int(hunk_match.group(1))
|
123
|
+
old_count = int(hunk_match.group(2) or "1")
|
124
|
+
new_start = int(hunk_match.group(3))
|
125
|
+
new_count = int(hunk_match.group(4) or "1")
|
126
|
+
|
127
|
+
old_current = old_start
|
128
|
+
new_current = new_start
|
129
|
+
hunk_index += 1
|
130
|
+
continue
|
131
|
+
|
132
|
+
# 解析变更行
|
133
|
+
change_match = CHANGE_LINE.match(line)
|
134
|
+
if change_match:
|
135
|
+
change_type = change_match.group(1)
|
136
|
+
content = change_match.group(2)
|
137
|
+
|
138
|
+
if change_type == " ":
|
139
|
+
# 上下文行 / 中间行
|
140
|
+
changes.append(
|
141
|
+
Change(
|
142
|
+
old=old_current,
|
143
|
+
new=new_current,
|
144
|
+
line=content,
|
145
|
+
hunk=hunk_index,
|
146
|
+
)
|
147
|
+
)
|
148
|
+
old_current += 1
|
149
|
+
new_current += 1
|
150
|
+
elif change_type == "-":
|
151
|
+
# 删除行
|
152
|
+
changes.append(
|
153
|
+
Change(
|
154
|
+
old=old_current, new=None, line=content, hunk=hunk_index
|
155
|
+
)
|
156
|
+
)
|
157
|
+
old_current += 1
|
158
|
+
elif change_type == "+":
|
159
|
+
# 新增行
|
160
|
+
changes.append(
|
161
|
+
Change(
|
162
|
+
old=None, new=new_current, line=content, hunk=hunk_index
|
163
|
+
)
|
164
|
+
)
|
165
|
+
new_current += 1
|
166
|
+
|
167
|
+
if header and changes:
|
168
|
+
diffs.append(
|
169
|
+
Diff(
|
170
|
+
header=header,
|
171
|
+
changes=changes,
|
172
|
+
text=text,
|
173
|
+
hunks=changes_to_hunks(changes),
|
174
|
+
)
|
175
|
+
)
|
176
|
+
|
177
|
+
except StopIteration:
|
178
|
+
break
|
179
|
+
|
180
|
+
return diffs if diffs else None
|
181
|
+
|
182
|
+
|
183
|
+
def parse_patch(text: str) -> Patch:
|
184
|
+
"""
|
185
|
+
Parse a patch file
|
186
|
+
Diiference between this and whatthepatch.parse_patch is that this function also
|
187
|
+
returns the sha, author, date and message of the commit
|
188
|
+
"""
|
189
|
+
|
190
|
+
lines = text.splitlines()
|
191
|
+
|
192
|
+
idx = 0
|
193
|
+
for i, line in enumerate(lines):
|
194
|
+
# 这里考虑 git log 格式和 git format-patch 格式
|
195
|
+
if (
|
196
|
+
git_diffcmd_header.match(line)
|
197
|
+
or spliter_line.match(line)
|
198
|
+
or unified_diff_header.match(line)
|
199
|
+
):
|
200
|
+
idx = i
|
201
|
+
break
|
202
|
+
|
203
|
+
else:
|
204
|
+
# raise ValueError(
|
205
|
+
# "No diff --git line found, check if the input is a valid patch"
|
206
|
+
# )
|
207
|
+
idx = len(lines) + 1
|
208
|
+
|
209
|
+
git_message_lines: list[str] = []
|
210
|
+
if idx == 0:
|
211
|
+
return Patch(
|
212
|
+
sha=None,
|
213
|
+
author=None,
|
214
|
+
date=None,
|
215
|
+
subject=None,
|
216
|
+
message=None,
|
217
|
+
# diff=[wtp_diff_to_diff(diff) for diff in wtp_parse_patch(text)],
|
218
|
+
diff=parse_unified_diff(text),
|
219
|
+
)
|
220
|
+
else:
|
221
|
+
git_message_lines = lines[:idx]
|
222
|
+
|
223
|
+
message = "\n".join(git_message_lines)
|
224
|
+
|
225
|
+
sha_line = git_message_lines.pop(0)
|
226
|
+
if sha_line.startswith("From ") or sha_line.startswith("commit "):
|
227
|
+
sha = sha_line.split(" ")[1]
|
228
|
+
else:
|
229
|
+
sha = None
|
230
|
+
|
231
|
+
author_line = git_message_lines.pop(0)
|
232
|
+
if author_line.startswith("Author: ") or author_line.startswith("From:"):
|
233
|
+
author = " ".join(author_line.split(" ")[1:])
|
234
|
+
else:
|
235
|
+
author = None
|
236
|
+
|
237
|
+
date_line = git_message_lines.pop(0)
|
238
|
+
if date_line.startswith("Date: "):
|
239
|
+
date_str = date_line.split("Date: ")[1]
|
240
|
+
# 解析 Thu, 7 Mar 2024 15:41:57 +0800 或 Tue Feb 2 16:07:37 2021 +0100
|
241
|
+
# if "," in date_str:
|
242
|
+
# date_fromat = "%a, %d %b %Y %H:%M:%S %z"
|
243
|
+
# else:
|
244
|
+
# date_fromat = "%a %b %d %H:%M:%S %Y %z"
|
245
|
+
|
246
|
+
# date = datetime.datetime.strptime(date_str.strip(), date_fromat)
|
247
|
+
date = date_str.strip()
|
248
|
+
else:
|
249
|
+
date = None
|
250
|
+
|
251
|
+
# 如果接下来的一行以 Subject 开头,则直接解析出 subject
|
252
|
+
if git_message_lines[0].startswith("Subject: "):
|
253
|
+
subject = git_message_lines.pop(0).split("Subject: ")[1]
|
254
|
+
else:
|
255
|
+
# 否则找到剩余的行里第一个非换行/非空行作为 subject
|
256
|
+
subject = None
|
257
|
+
for line in git_message_lines:
|
258
|
+
if line.strip() != "":
|
259
|
+
subject = line
|
260
|
+
break
|
261
|
+
|
262
|
+
return Patch(
|
263
|
+
sha=sha.strip() if sha else None,
|
264
|
+
author=author.strip() if author else None,
|
265
|
+
date=date,
|
266
|
+
subject=subject.strip() if subject else None,
|
267
|
+
message=message,
|
268
|
+
diff=[wtp_diff_to_diff(diff) for diff in wtp_parse_patch(text)],
|
269
|
+
)
|
Patche/utils/resolve.py
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
from Patche.app import logger
|
2
|
+
from Patche.config import settings
|
3
|
+
from Patche.model import ApplyResult, Hunk, Line
|
4
|
+
from Patche.utils.common import find_list_positions
|
5
|
+
|
6
|
+
|
7
|
+
def apply_change(
|
8
|
+
hunk_list: list[Hunk],
|
9
|
+
target: list[Line],
|
10
|
+
reverse: bool = False,
|
11
|
+
flag_hunk_list: list[int] = None,
|
12
|
+
fuzz: int = 2, # set fuzz=2 according GNU Patch
|
13
|
+
) -> ApplyResult:
|
14
|
+
"""Apply a diff to a target string."""
|
15
|
+
|
16
|
+
flag_hunk_list = [] if flag_hunk_list is None else flag_hunk_list
|
17
|
+
|
18
|
+
if fuzz > settings.max_diff_lines or fuzz < 0:
|
19
|
+
raise Exception(f"fuzz value should be less than {settings.max_diff_lines}")
|
20
|
+
|
21
|
+
if reverse:
|
22
|
+
for hunk in hunk_list:
|
23
|
+
for change in hunk.context + hunk.middle + hunk.post:
|
24
|
+
change.old, change.new = change.new, change.old
|
25
|
+
|
26
|
+
# 然后对每个hunk进行处理,添加偏移
|
27
|
+
failed_hunk_list: list[Hunk] = []
|
28
|
+
last_pos = None
|
29
|
+
|
30
|
+
last_offset = 0
|
31
|
+
line_count_diff = 0
|
32
|
+
for hunk in hunk_list:
|
33
|
+
|
34
|
+
current_hunk_fuzz = 0
|
35
|
+
|
36
|
+
while current_hunk_fuzz <= fuzz:
|
37
|
+
|
38
|
+
# hunk.context = hunk.context[1:]
|
39
|
+
# hunk.post = hunk.post[: fuzz - current_hunk_fuzz]
|
40
|
+
|
41
|
+
logger.debug(
|
42
|
+
f"current_fuzz: {current_hunk_fuzz} len(hunk.context): {len(hunk.context)} len(hunk.post): {len(hunk.post)}"
|
43
|
+
)
|
44
|
+
|
45
|
+
changes_to_search = hunk.context + hunk.middle + hunk.post
|
46
|
+
pos_list = find_list_positions(
|
47
|
+
[line.content for line in target],
|
48
|
+
[change.line for change in changes_to_search if change.old is not None],
|
49
|
+
)
|
50
|
+
|
51
|
+
if len(pos_list) != 0:
|
52
|
+
break
|
53
|
+
|
54
|
+
current_hunk_fuzz += 1
|
55
|
+
|
56
|
+
if current_hunk_fuzz <= fuzz:
|
57
|
+
hunk.context = hunk.context[1:]
|
58
|
+
hunk.post = hunk.post[: 3 - current_hunk_fuzz]
|
59
|
+
|
60
|
+
# 初始位置是 context 的第一个
|
61
|
+
# 注意,前几个有可能是空
|
62
|
+
pos_origin = None
|
63
|
+
for change in changes_to_search:
|
64
|
+
if change.old is not None:
|
65
|
+
pos_origin = change.old
|
66
|
+
break
|
67
|
+
|
68
|
+
# TODO: 这里不太对,要想一下怎么处理,不应该是加入 failed hunk list
|
69
|
+
# 仅在 -F 3 且只有添加行 的情况下出现(指与 GNU patch 行为不一致)
|
70
|
+
# 也可以看一下这样的情况有多少
|
71
|
+
if current_hunk_fuzz == fuzz and pos_origin is not None:
|
72
|
+
# failed_hunk_list.append(hunk)
|
73
|
+
# logger.debug(f"Could not determine pos_origin")
|
74
|
+
# logger.warning(f"Apply failed with hunk {hunk.index}")
|
75
|
+
# continue
|
76
|
+
for change in changes_to_search:
|
77
|
+
if change.new is not None:
|
78
|
+
pos_origin = change.new
|
79
|
+
break
|
80
|
+
|
81
|
+
# 使用上一次偏移加上行数变化差值
|
82
|
+
min_offset = last_offset
|
83
|
+
else:
|
84
|
+
if len(pos_list) == 0:
|
85
|
+
failed_hunk_list.append(hunk)
|
86
|
+
logger.debug(f"Could not determine proper position")
|
87
|
+
logger.warning(f"Apply failed with hunk {hunk.index}")
|
88
|
+
continue
|
89
|
+
|
90
|
+
offset_list = [
|
91
|
+
pos + 1 - pos_origin for pos in pos_list
|
92
|
+
] # 确认这里是否需要 1?
|
93
|
+
|
94
|
+
# 计算最小 offset
|
95
|
+
min_offset = None
|
96
|
+
for offset in offset_list:
|
97
|
+
if min_offset is None or abs(offset) < abs(min_offset):
|
98
|
+
min_offset = offset
|
99
|
+
|
100
|
+
if reverse:
|
101
|
+
min_offset += line_count_diff
|
102
|
+
pos_origin -= line_count_diff
|
103
|
+
|
104
|
+
last_offset = min_offset
|
105
|
+
|
106
|
+
# 更新行数变化差值
|
107
|
+
hunk_add_count = sum(
|
108
|
+
1 for c in changes_to_search if c.old is None and c.new is not None
|
109
|
+
)
|
110
|
+
hunk_del_count = sum(
|
111
|
+
1 for c in changes_to_search if c.new is None and c.old is not None
|
112
|
+
)
|
113
|
+
line_count_diff += hunk_del_count - hunk_add_count
|
114
|
+
|
115
|
+
logger.info(
|
116
|
+
f"Apply hunk {hunk.index} with offset {min_offset} fuzz {current_hunk_fuzz} line_diff {line_count_diff}"
|
117
|
+
)
|
118
|
+
|
119
|
+
# 直接按照 pos 进行替换
|
120
|
+
# 选择 offset 最小的 pos
|
121
|
+
pos_new = pos_origin + min_offset - 1
|
122
|
+
|
123
|
+
# 处理 pos_new 小于 last_pos 的情况
|
124
|
+
logger.debug(f"pos_origin: {pos_origin}, last_pos: {last_pos}")
|
125
|
+
if last_pos is None:
|
126
|
+
last_pos = pos_new
|
127
|
+
elif pos_new < last_pos:
|
128
|
+
# 特别主要 pos_new 小于 last_pos 的情况
|
129
|
+
logger.warning(f"Apply failed with hunk {hunk.index}")
|
130
|
+
logger.error(f"pos: {pos_new} is greater than last_pos: {last_pos}")
|
131
|
+
failed_hunk_list.append(hunk)
|
132
|
+
continue
|
133
|
+
else:
|
134
|
+
last_pos = pos_new
|
135
|
+
|
136
|
+
old_lines = [
|
137
|
+
change.line
|
138
|
+
for change in hunk.context + hunk.middle + hunk.post
|
139
|
+
if change.old is not None
|
140
|
+
]
|
141
|
+
new_lines = [
|
142
|
+
change.line
|
143
|
+
for change in hunk.context + hunk.middle + hunk.post
|
144
|
+
if change.new is not None
|
145
|
+
]
|
146
|
+
|
147
|
+
# 检查 pos_new 位置的行是否和 old_lines 一致
|
148
|
+
for i in range(len(old_lines)):
|
149
|
+
if target[pos_new + i].content != old_lines[i]:
|
150
|
+
raise Exception(
|
151
|
+
f'line {pos_new + i}, "{target[pos_new + i].content}" does not match "{old_lines[i]}"'
|
152
|
+
)
|
153
|
+
|
154
|
+
# 以切片的方式进行替换
|
155
|
+
target = (
|
156
|
+
target[:pos_new]
|
157
|
+
+ [
|
158
|
+
Line(index=pos_new + i, content=new_lines[i])
|
159
|
+
for i in range(len(new_lines))
|
160
|
+
]
|
161
|
+
+ target[pos_new + len(old_lines) :]
|
162
|
+
)
|
163
|
+
|
164
|
+
return ApplyResult(
|
165
|
+
new_line_list=target,
|
166
|
+
conflict_hunk_num_list=[],
|
167
|
+
failed_hunk_list=failed_hunk_list,
|
168
|
+
)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: mseep-patche
|
3
|
+
Version: 1.0.1
|
4
|
+
Summary: Modern Patch in Python
|
5
|
+
Author-Email: mseep <support@skydeck.ai>
|
6
|
+
License: MIT
|
7
|
+
Requires-Python: >=3.10
|
8
|
+
Requires-Dist: typer[all]>=0.9.0
|
9
|
+
Requires-Dist: pydantic>=2.5.3
|
10
|
+
Requires-Dist: pydantic-settings>=2.2.1
|
11
|
+
Requires-Dist: whatthepatch-pydantic==1.0.6a3
|
12
|
+
Description-Content-Type: text/plain
|
13
|
+
|
14
|
+
Package managed by MseeP.ai
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Patche/__init__.py,sha256=PVoMA8KWQKPFthAyEIn4oNZATeGNTGXVuqLfqoOjfmE,34
|
2
|
+
Patche/__main__.py,sha256=QXfE3TKpFZsct7wDbpv5g3tQGmrUkBMjL_nXg_wJvEM,28
|
3
|
+
Patche/__version__.py,sha256=wtfcRFm73_vwwNMAiQol_VGC7QetgMQWRsGYiTuqF0c,185
|
4
|
+
Patche/app.py,sha256=I5AjgCmHmIE6jPaYYdbRwBL4dv5BK3nB4fKFDgI3u_w,838
|
5
|
+
Patche/commands/apply.py,sha256=POcKV3oxtqD6jbkrujKycOnG9ruk1Wj6QadXlNQCb4U,3509
|
6
|
+
Patche/commands/help.py,sha256=nEGX9GHT2CJHchLh02ZJ4RxPwWf84j6j4YpSFwS6cLo,214
|
7
|
+
Patche/commands/show.py,sha256=Io-9vruhgrPf5GalJTfEm6KNseQ2LY6Eu0MiDLtcSFs,1105
|
8
|
+
Patche/config.py,sha256=6k9RZ8skRTQ8hPYI1I63PkupsLkZSCmVxIhJZdwRVNU,499
|
9
|
+
Patche/mcp/__init__.py,sha256=Y6bkduOn9Ljy76x8bOFGrcjx4RFB8zrY_FCVC7grfEY,815
|
10
|
+
Patche/mcp/__main__.py,sha256=3xkjNDGmST-F8nTIpnE0OVBBBGL3sjToNbc-QRebi9k,36
|
11
|
+
Patche/mcp/model.py,sha256=p_uTVFVB9PubhFJaUbqNeOlJr63WvTK70lmLDx7uLxM,472
|
12
|
+
Patche/mcp/prompts.py,sha256=VFc0h6ayMmWvHg-NKTJgoCFS7KzSA6ttzy5JK8TT7nM,7726
|
13
|
+
Patche/mcp/server.py,sha256=5fhkLIAgC5jf6qGgV0dh9lqEd13VvycUaBTdPjXYt_Y,3450
|
14
|
+
Patche/mcp/tools.py,sha256=u7gNMd9NEXGpI20atx3pIEjeZLMCo6bUvtrSs_eoFy8,4886
|
15
|
+
Patche/model.py,sha256=Dm-LneXe3idcxNRbAhZ01Z6hqw-HDioHeJ07h2aPdvM,1842
|
16
|
+
Patche/utils/common.py,sha256=_4o3z2Dq-9qG2ahX3UmIfShTO1mesZ3DXGu0EIeS6BE,2020
|
17
|
+
Patche/utils/header.py,sha256=t4wlitYDaZRq2zGlP0FqIP2ihz83eg_7jJ9VDuXnIYY,1075
|
18
|
+
Patche/utils/parse.py,sha256=RVWxCAbweEDN7y6RQ44R-rRw-GDLFvRamMFxW9hOveA,8573
|
19
|
+
Patche/utils/resolve.py,sha256=4bpUYtSfDK5dwBldw4essjirI4zbMOxutiMBnhPubkw,5854
|
20
|
+
mseep_patche-1.0.1.dist-info/METADATA,sha256=GA-Wovcm8kAphOFhOuZs-zFpStPivRMS53Z_Jyyk5V4,381
|
21
|
+
mseep_patche-1.0.1.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
22
|
+
mseep_patche-1.0.1.dist-info/entry_points.txt,sha256=OhS7Z9mx7By8K1v0_XTqzwGs7v5BQEocPpu20F0WrOE,100
|
23
|
+
mseep_patche-1.0.1.dist-info/licenses/LICENSE,sha256=2I7sSSPi_J8S7pOQIvPdaRQubMmIpsDI6qNblsWv5ek,1066
|
24
|
+
mseep_patche-1.0.1.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 jingfelix
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|