两份锁差在哪
(每道题开头都有同一段:parse_ver 把「1.4.0」变成能比大小的元组,satisfies(版本, 约束) 判一个版本满不满足「>=1.4,<2」这种约束,split_req 把「httpkit>=1.4」切成名字和约束;REPO 是上面那个小仓库。)
(candidates 列出仓库里满足约束的版本(从低到高);resolve(清单) 逐个选最高可用版本、把它的依赖加进队列、约束越收越紧,交回 {包: 版本},无解交回 None。它不回溯——pip 会。)
(这一节多了:parse_requirements 读清单文本(跳过空行和 # 注释),freeze 把选好的版本写成锁文件文本,parse_lock 读回来,diff_lock 比两份锁。)
A 机器和 B 机器各交了一份锁。比一比:
def parse_ver(s):
return tuple(int(x) for x in s.split("."))
def satisfies(ver, spec):
v = parse_ver(ver)
for part in spec.split(","):
part = part.strip()
if not part:
continue
for op in (">=", "<=", "==", "!=", ">", "<"):
if part.startswith(op):
w = parse_ver(part[len(op):])
break
ok = {">=": v >= w, "<=": v <= w, "==": v == w, "!=": v != w, ">": v > w, "<": v < w}[op]
if not ok:
return False
return True
def split_req(line):
i = 0
while i < len(line) and (line[i].isalnum() or line[i] in "_-"):
i += 1
return line[:i], line[i:].replace(" ", "")
REPO = {
"urlkit": {"1.9.0": [], "2.0.0": [], "2.1.0": []},
"charkit": {"4.0.0": [], "5.1.0": []},
"httpkit": {"1.3.0": ["urlkit<2", "charkit<5"], "1.4.0": ["urlkit<2", "charkit>=4"], "1.5.0": ["urlkit>=2", "charkit>=5"]},
"templ": {"3.0.0": [], "3.1.0": []},
"webapp": {"2.3.0": ["httpkit>=1.3,<1.5", "templ>=3"], "3.0.0": ["httpkit>=1.5", "templ>=3.1"]},
}
def candidates(name, spec):
return sorted((v for v in REPO.get(name, {}) if satisfies(v, spec)), key=parse_ver)
def resolve(reqs):
spec = {}
for r in reqs:
n, s = split_req(r)
spec[n] = s if n not in spec else spec[n] + "," + s
chosen = {}
todo = list(spec)
while todo:
n = todo.pop(0)
cands = candidates(n, spec.get(n, ""))
if not cands:
return None
v = cands[-1]
if chosen.get(n) == v:
continue
chosen[n] = v
for d in REPO[n][v]:
dn, ds = split_req(d)
spec[dn] = ds if dn not in spec else spec[dn] + "," + ds
todo.append(dn)
for n, v in chosen.items():
if not satisfies(v, spec[n]):
return None
return chosen
def parse_requirements(text):
reqs = []
for line in text.split("\n"):
line = line.split("#")[0].strip()
if line:
reqs.append(line)
return reqs
def freeze(chosen):
return "\n".join(n + "==" + chosen[n] for n in sorted(chosen))
def parse_lock(text):
lock = {}
for line in parse_requirements(text):
n, s = split_req(line)
lock[n] = s[2:]
return lock
def diff_lock(a, b):
changed = sorted(n for n in a if n in b and a[n] != b[n])
added = sorted(n for n in b if n not in a)
removed = sorted(n for n in a if n not in b)
return changed, added, removed
a = parse_lock("charkit==5.1.0\nhttpkit==1.4.0\ntempl==3.1.0\nurlkit==1.9.0\nwebapp==2.3.0\n")
b = parse_lock("charkit==5.1.0\nhttpkit==1.5.0\ntempl==3.1.0\nurlkit==2.1.0\nwebapp==3.0.0\nextra==0.1.0\n")
changed, added, removed = diff_lock(a, b)
print(",".join(changed) + "/" + ",".join(added) + "/" + str(len(removed)))
全部评论