两个环境各装各的
(每道题开头都有同一段:parse_ver 把「1.4.0」变成能比大小的元组,satisfies(版本, 约束) 判一个版本满不满足「>=1.4,<2」这种约束,split_req 把「httpkit>=1.4」切成名字和约束;REPO 是上面那个小仓库。)
(candidates 列出仓库里满足约束的版本(从低到高);resolve(清单) 逐个选最高可用版本、把它的依赖加进队列、约束越收越紧,交回 {包: 版本},无解交回 None。它不回溯——pip 会。)
贯穿全条的小仓库(五个假包):
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)项目甲清单 httpkit<1.5,项目乙清单 webapp>=3。各自解析,看 urlkit 各是哪个版本:
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
a = resolve(["httpkit<1.5"])
b = resolve(["webapp>=3"])
print(a["urlkit"] + "/" + b["urlkit"] + "/" + str(a["urlkit"] == b["urlkit"]))
全部评论