Created
May 1, 2024 16:39
-
-
Save rsiemens/7b37af435cdefc845e58c3ab3e2d32db to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
from queue import Queue | |
from collections import defaultdict | |
from pkg_resources import Requirement | |
META_URL = 'https://pypi.org/pypi/{req}/json' | |
class Digraph: | |
def __init__(self): | |
self.graph = defaultdict(set) | |
def add_edge(self, source, to): | |
self.graph[source].add(to) | |
def vertices(self): | |
return len(self.graph) | |
def edges(self): | |
total = 0 | |
for k in self.graph: | |
total += len(self.graph[k]) | |
return total | |
def adj(self, vert): | |
return self.graph[vert] | |
class BreadthFirstGraphBuilder: | |
def __init__(self, req): | |
self.req = req | |
self.visited = set() | |
self.digraph = Digraph() | |
def build(self): | |
self._bfs(self.req) | |
self.visited = set() | |
self._display(self.req) | |
def _display(self, req, depth=0): | |
self.visited.add(req) | |
print((" " * depth) + req) | |
for adj in self.digraph.adj(req): | |
if adj not in self.visited: | |
self._display(adj, depth=depth+1) | |
def _bfs(self, req): | |
q = Queue() | |
q.put(req) | |
self.visited.add(req) | |
while not q.empty(): | |
n = q.get() | |
self._visit(n) | |
for adj in self.digraph.adj(n): | |
if adj not in self.visited: | |
self.visited.add(adj) | |
q.put(adj) | |
def _visit(self, req): | |
meta = self._get_meta(req) | |
deps = self._get_reqs(meta) | |
for dep in deps: | |
self.digraph.add_edge(req, dep) | |
def _get_meta(self, req): | |
url = META_URL.format(req=req) | |
res = requests.get(url) | |
res.raise_for_status() | |
return res.json() | |
def _get_reqs(self, meta): | |
ver_reqs = meta['info']['requires_dist'] | |
fixed_reqs = [] | |
if ver_reqs: | |
for r in ver_reqs: | |
p = Requirement.parse(r) | |
if p.marker and not p.marker.evaluate({'extra': None}): | |
continue | |
else: | |
fixed_reqs.append(p.name) | |
return fixed_reqs | |
if __name__ == '__main__': | |
import sys | |
req = sys.argv[1] | |
builder = BreadthFirstGraphBuilder(req) | |
builder.build() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment