Spaces:
Runtime error
Runtime error
performance optimization using aiohttp and change api endpoint
Browse files- Pipfile +1 -0
- Pipfile.lock +96 -36
- README.md +7 -2
- app.py +7 -10
- py_code_analyzer/code_fetcher.py +37 -34
- py_code_analyzer/code_imports_analyzer.py +49 -14
Pipfile
CHANGED
@@ -9,6 +9,7 @@ requests = "*"
|
|
9 |
networkx = "*"
|
10 |
pyvis = {editable = true, path = "./pyvis"}
|
11 |
aiohttp = {extras = ["speedups"], version = "*"}
|
|
|
12 |
|
13 |
[dev-packages]
|
14 |
black = "*"
|
|
|
9 |
networkx = "*"
|
10 |
pyvis = {editable = true, path = "./pyvis"}
|
11 |
aiohttp = {extras = ["speedups"], version = "*"}
|
12 |
+
pybase64 = "*"
|
13 |
|
14 |
[dev-packages]
|
15 |
black = "*"
|
Pipfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
{
|
2 |
"_meta": {
|
3 |
"hash": {
|
4 |
-
"sha256": "
|
5 |
},
|
6 |
"pipfile-spec": 6,
|
7 |
"requires": {
|
@@ -193,28 +193,6 @@
|
|
193 |
],
|
194 |
"version": "==0.2.0"
|
195 |
},
|
196 |
-
"backports.zoneinfo": {
|
197 |
-
"hashes": [
|
198 |
-
"sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf",
|
199 |
-
"sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328",
|
200 |
-
"sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546",
|
201 |
-
"sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6",
|
202 |
-
"sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570",
|
203 |
-
"sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9",
|
204 |
-
"sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7",
|
205 |
-
"sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987",
|
206 |
-
"sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722",
|
207 |
-
"sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582",
|
208 |
-
"sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc",
|
209 |
-
"sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b",
|
210 |
-
"sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1",
|
211 |
-
"sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08",
|
212 |
-
"sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac",
|
213 |
-
"sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"
|
214 |
-
],
|
215 |
-
"markers": "python_version >= '3.6' and python_version < '3.9'",
|
216 |
-
"version": "==0.2.1"
|
217 |
-
},
|
218 |
"beautifulsoup4": {
|
219 |
"hashes": [
|
220 |
"sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30",
|
@@ -591,14 +569,6 @@
|
|
591 |
"markers": "python_version >= '3.7'",
|
592 |
"version": "==4.11.4"
|
593 |
},
|
594 |
-
"importlib-resources": {
|
595 |
-
"hashes": [
|
596 |
-
"sha256:b6062987dfc51f0fcb809187cffbd60f35df7acb4589091f154214af6d0d49d3",
|
597 |
-
"sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8"
|
598 |
-
],
|
599 |
-
"markers": "python_version < '3.9'",
|
600 |
-
"version": "==5.7.1"
|
601 |
-
},
|
602 |
"ipykernel": {
|
603 |
"hashes": [
|
604 |
"sha256:6f42070a5d87ecbf4a2fc27a7faae8d690fd3794825a090ddf6b00b9678a5b69",
|
@@ -1140,6 +1110,96 @@
|
|
1140 |
"markers": "python_version >= '3.7'",
|
1141 |
"version": "==8.0.0"
|
1142 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1143 |
"pycares": {
|
1144 |
"hashes": [
|
1145 |
"sha256:03490be0e7b51a0c8073f877bec347eff31003f64f57d9518d419d9369452837",
|
@@ -1345,7 +1405,7 @@
|
|
1345 |
"sha256:4c586de507202505346f3e32d1363eb9ed6932f0c2f63184dea88983ff4971e2",
|
1346 |
"sha256:d2bbd99c320a2532ac71ff6a3164867884357da3e3301f0240090c5d2fdac7ec"
|
1347 |
],
|
1348 |
-
"markers": "
|
1349 |
"version": "==12.4.4"
|
1350 |
},
|
1351 |
"semver": {
|
@@ -1494,7 +1554,7 @@
|
|
1494 |
"sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708",
|
1495 |
"sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"
|
1496 |
],
|
1497 |
-
"markers": "python_version
|
1498 |
"version": "==4.2.0"
|
1499 |
},
|
1500 |
"tzdata": {
|
@@ -1518,7 +1578,7 @@
|
|
1518 |
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
|
1519 |
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
|
1520 |
],
|
1521 |
-
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and
|
1522 |
"version": "==1.26.9"
|
1523 |
},
|
1524 |
"validators": {
|
@@ -1632,7 +1692,7 @@
|
|
1632 |
"sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad",
|
1633 |
"sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"
|
1634 |
],
|
1635 |
-
"markers": "python_version
|
1636 |
"version": "==3.8.0"
|
1637 |
}
|
1638 |
},
|
@@ -1890,7 +1950,7 @@
|
|
1890 |
"sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708",
|
1891 |
"sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"
|
1892 |
],
|
1893 |
-
"markers": "python_version
|
1894 |
"version": "==4.2.0"
|
1895 |
}
|
1896 |
}
|
|
|
1 |
{
|
2 |
"_meta": {
|
3 |
"hash": {
|
4 |
+
"sha256": "f46d041868e3a17ffed758287363ab28b314e33d2594c5880248d6571cf69cf0"
|
5 |
},
|
6 |
"pipfile-spec": 6,
|
7 |
"requires": {
|
|
|
193 |
],
|
194 |
"version": "==0.2.0"
|
195 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
"beautifulsoup4": {
|
197 |
"hashes": [
|
198 |
"sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30",
|
|
|
569 |
"markers": "python_version >= '3.7'",
|
570 |
"version": "==4.11.4"
|
571 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
572 |
"ipykernel": {
|
573 |
"hashes": [
|
574 |
"sha256:6f42070a5d87ecbf4a2fc27a7faae8d690fd3794825a090ddf6b00b9678a5b69",
|
|
|
1110 |
"markers": "python_version >= '3.7'",
|
1111 |
"version": "==8.0.0"
|
1112 |
},
|
1113 |
+
"pybase64": {
|
1114 |
+
"hashes": [
|
1115 |
+
"sha256:002402c6e32b8325410a7fe7633c94f7ec265ec5c164d931853a5c278d47d177",
|
1116 |
+
"sha256:03aeffad37d282cf8af76304176bb3df7a8567bbaf9aebc3766f0229672500fa",
|
1117 |
+
"sha256:06c9750db1881f8ea5568715871c04788c8f9f01f55f7d466b7aa2dd9461436b",
|
1118 |
+
"sha256:074b5915c80317a69044c64d6521754242093f40454af75404072ef4b763a476",
|
1119 |
+
"sha256:083bd31391501e77789cdef6989c1ac85d605f12dfaec58ecf003b56fcecd8a1",
|
1120 |
+
"sha256:086d9a151e165ba5ac3b23f69927e8404edcd196b5f10ef5601a029fec21dcc3",
|
1121 |
+
"sha256:115b486095ead72a788f7d9ff43d73457813755eab05846ad575ae0d9361e218",
|
1122 |
+
"sha256:138c791a53f58b3293bed0251d61f7e42f95b03abf5048b06b1b5ffc8ba64c1c",
|
1123 |
+
"sha256:14f06c398a9c95f62075ec54592da7dccab813cc68f27c23960c40a220a7d64c",
|
1124 |
+
"sha256:17927f60dd0688062e39fcc1db31a00c90b6073d2f0718cdfb44b30bcfc3a5f4",
|
1125 |
+
"sha256:1d4be51b4455697b1f99a15e42f95cb37f383832993d6d4e2f12df3264db066b",
|
1126 |
+
"sha256:1d53038944833d1ed7f06651fd0947cddd0f98d508809f5a4028fd9966c607e8",
|
1127 |
+
"sha256:1eb2bc17d3bf9523ec92640c62332b0e11192fe2fead2dd5f0861593719e4e2b",
|
1128 |
+
"sha256:223fa4e6951d71e6b857b4b67c99496f1aa7e688c07798256d6082d623cfd4ec",
|
1129 |
+
"sha256:227d86fbc8aae760277c08c893abfebbf95e49edcb55e8dc0941121d82e49f40",
|
1130 |
+
"sha256:2ba652cf1c9c82bb5f2772c7d69e50d99d62c57312c1c0637411d0f70fa3abe3",
|
1131 |
+
"sha256:2be7f47ae45b9aeba342773c6044ca03338620812a5257b2e221c1bb9665a7c8",
|
1132 |
+
"sha256:2e7b3dc73cc149a7e6543cda0d006e3b366ccad42efaa4fa3df2d2ebbc5b2e35",
|
1133 |
+
"sha256:4289b8149ea83fad9f0d198c91542585ba76ae1e6533997c63e0115d4d1ab79b",
|
1134 |
+
"sha256:428a80f731732334d2cc48779c6b411014afcfcc54b048af2c41cededba3fe05",
|
1135 |
+
"sha256:469020014cc82eb95bcb227f1a3b41cdfd3a90147b83757cc2c939f3ed722d03",
|
1136 |
+
"sha256:4908de8e71a4ed7319d49482424bf51dca41b4bb729538388878325d1cee4eac",
|
1137 |
+
"sha256:4a8c9960ae2944c69bedff36dac03af8beab7cce4f1b7a9708abdd48fb919277",
|
1138 |
+
"sha256:5128d4dc733406777c968da211ae07255e213cd960a0b2e9fdb9d18948b6c198",
|
1139 |
+
"sha256:520af879876b3b4d3808e1a1af3825d98cc7653330b44a1f7dc8806aceec2cb5",
|
1140 |
+
"sha256:52a5abec54b4871d829b9fed0ae1d23ce9285e309d190c7e999b67c522bb63f5",
|
1141 |
+
"sha256:553cb711ad3933ccc5ae6674254793cd7ba9b978b851cbc2716c47b16a108f67",
|
1142 |
+
"sha256:5f85bd8e1a133552e6fb94cee60b69d337469d294f4708e7e2ce504cd013d81c",
|
1143 |
+
"sha256:60f002841f8f02883ad92d3c8e8e556a567b6745c56fc3ce39079eb42fb206e6",
|
1144 |
+
"sha256:60f15e1fa0664f4b2fafdf2208b624207a5c76bd928b47202003f4c71132a2f5",
|
1145 |
+
"sha256:6245c3182dd5d8563e0d7a17946db6ccf0327c4302cc4100b4b2b4c7f81f2a9e",
|
1146 |
+
"sha256:6310792de5ce27ffc420a0f0ea90a2b3b4d6d025061f608192533549bc03d124",
|
1147 |
+
"sha256:631424e78da38b90cd09905abb7d8b8b9968924a061067a86cbde4e059102ae8",
|
1148 |
+
"sha256:6a663cfba11ae2d860a716548f0a17b2d9403a5817e769c10368894239afafb6",
|
1149 |
+
"sha256:6b8f126849ff3446ea1a0f2b6c92bf9486447144cf1e02c2b612e2267a4dcec1",
|
1150 |
+
"sha256:71fe6a13add14c2a7ef0d800d1b0d73e1711dc0a4fb45a29c5a3cf586eb78a34",
|
1151 |
+
"sha256:74754b0b6cc32970b43d1eb45494d4d44730a43bf3e4ee12a9ad8c737837f83e",
|
1152 |
+
"sha256:76978e23187754fda63cbbbc824dc66ad945cb8e141b57e1970e1c885fd09b35",
|
1153 |
+
"sha256:77741ca9d24a3cc43be7370be9d70fef335b646452b23a0601327e09b1acbcc7",
|
1154 |
+
"sha256:779347de5125b16611d5410612e660aa7974a52cb14a10acab1cb7b123560b16",
|
1155 |
+
"sha256:7ab7bfc4c0f4182d2142ed15e6afa17536c9258954ad1d23dc936ed411ac16ee",
|
1156 |
+
"sha256:7c7e7ddeb9ba2c962e2eed139f91073605f6133f071fb522df977d10d0ca415d",
|
1157 |
+
"sha256:7e399994df61d6e0dfabd06fe2a4b461e815e62ef5ebfc60e43419906e31b17f",
|
1158 |
+
"sha256:7eeaabee388db02890746022b106834476a332f0b718de90b775bd5fe1140609",
|
1159 |
+
"sha256:7fbafe9c33f484a97418ec06e3e46b98ff3f8e7ca65848c84fc4b6c3833acb1f",
|
1160 |
+
"sha256:80c8dedda291c2967242de4c9bdddaa5c8151b238a2d83a4623d48393a2b31fa",
|
1161 |
+
"sha256:8252c0d3116734484889728eebe125e6c5d2f3f1cc7cb8dbd110342df079ef94",
|
1162 |
+
"sha256:84dcbdc19e45eacb7917afe0e76db70c5336e7375314792a9fa69c37ca5bbf56",
|
1163 |
+
"sha256:8e067f9ca6e658151fb8c0a6405aff98df0e6d4a9726b65e8a1390326fd6c38c",
|
1164 |
+
"sha256:8f1f2e29e7a17b9ec4a272beba4e98e924ae2011ed13a832462c592ef4180a00",
|
1165 |
+
"sha256:90ebc76a1874c53c5bd7831ce2b5884dee113feaeca7b4cf40c958e5e7bad832",
|
1166 |
+
"sha256:92cbd5b13f70658f9d130a39d67f4196bcf0cf83ed724420e96149874b568c63",
|
1167 |
+
"sha256:95e0e62c35acd8117f7f779c03bab4e12d4b0cc0249a57a2a2895996263a82d1",
|
1168 |
+
"sha256:983104702075c91af22dbdefa2ec4b99699126934f366c41e7bc05ad5e89e2e1",
|
1169 |
+
"sha256:994195cf1cbdb3f8658304cea731d93a2d5cae83612cddb90e6415953e03c459",
|
1170 |
+
"sha256:9a1168dec66aa4fb73062ca9a031ca0e028e90429bd5333e307e2d7c41ab7f69",
|
1171 |
+
"sha256:9b47d2d0f0a0e2c1c74f4bff681dd4cc922ae9a4f6967444cfb3c80ac9fe2d54",
|
1172 |
+
"sha256:9ccc61ea23deac82fa96c0ab0005e88451241bd00775c21f1d334a93485e945a",
|
1173 |
+
"sha256:a08c5cc6df5a667f261ac1d2c23ff59fd095b7e9d5b39525eaf8245ff3f8b202",
|
1174 |
+
"sha256:aa9e94fe7809584c5bd6c2cf1971e0be37065c518a491fd2f038e91d1697f5ac",
|
1175 |
+
"sha256:ad9aa7a054386a2b7d6eb109f538bce9759a53341262e8b0879b62f79d9d8da7",
|
1176 |
+
"sha256:aede141563e1ba320d400e1e74d0b3807e7fe04153e69a9606de19b7897307ea",
|
1177 |
+
"sha256:b27b86544c87c9a876c70d8aa1c780ed1c6a80e24842bcf45d1f2cd2d5216e8e",
|
1178 |
+
"sha256:b6e51e25fd8e83e2028d6d874af8059c1685f496520e137b87de3aded9d0055a",
|
1179 |
+
"sha256:b7fe9f93c250a74e82de61cce67acb4d5cff5a73db60c6707efe22193ad987a4",
|
1180 |
+
"sha256:b8c21cedb8271d9ebfa9787e3341cca282f96f00993f59062afa3da1782c8a31",
|
1181 |
+
"sha256:bdbf00344e81169b6b89cf4952dcea45b92a2e521e4ec9f6c35e221d3868045d",
|
1182 |
+
"sha256:bdf41018265b43495e5b709a13c1f09b18024c2a2d1ef5355a1c761ea2caa6c2",
|
1183 |
+
"sha256:befd983a5a7b6551355b6abe56723f7f9f12c580e02f126b7883b075bebff25c",
|
1184 |
+
"sha256:bf56503363852a744f85ad08fd20a0a286d2616aa4feb3c1f197e34d07c872bf",
|
1185 |
+
"sha256:d3fb7a2836cdcabb00ca8cb5faf9ed93b26d45865745e32eb70e404faf8a6ccf",
|
1186 |
+
"sha256:d505433a8b94dd8fff53d56b7f9e3f739e8a648bea204c487da08b69d681c160",
|
1187 |
+
"sha256:d5c29a701502a1a26a5bae69397f616c3510f6c3e478a32c4ae1dd8f7b6b515b",
|
1188 |
+
"sha256:d6d0b6b08933f3f908404a74a6befeff9d0c3fa145ed424e346f3bb09266e360",
|
1189 |
+
"sha256:d77d7b67421915a082fd41274dd94cef9c82c9dce03e4f06636543f16c399407",
|
1190 |
+
"sha256:db98ffd03ab10cf80844d7adee5c00ab73aa8ddc5c9685c705dcaeee2f85381a",
|
1191 |
+
"sha256:e88827ec2fd12db9d3f93dd692c8881f292e065a3e50892ac67d0b0da7489f7c",
|
1192 |
+
"sha256:ecae5643460762f4665d04087b59719e0cb43a1b8a407ca7c1b4c5d9e419416f",
|
1193 |
+
"sha256:edd27bb6cf81c4a29362b98965906fd2534d57cc37efd3b1d8364224ffaee4f2",
|
1194 |
+
"sha256:ee79b48c3a19e3f5ddf0c85e46f6c15c65d623b581dd0786c214d188e9539cad",
|
1195 |
+
"sha256:ef8a18c78f1e5e7f37ed6c08e6564216c5b19564f5bb212438f1eba0f19c9607",
|
1196 |
+
"sha256:f41afa7779e71d7176e174225298aeeeff0f5c871bc3e693070842b99ef2d935",
|
1197 |
+
"sha256:f420da3258085992dfbc0e050f145d0f1b601bfb1013d3ad8377c158a20a2d9d",
|
1198 |
+
"sha256:fa58addd890b20b922a2037169f530a91ed004b5c5d258fe3f896f4a6d57515f"
|
1199 |
+
],
|
1200 |
+
"index": "pypi",
|
1201 |
+
"version": "==1.2.2"
|
1202 |
+
},
|
1203 |
"pycares": {
|
1204 |
"hashes": [
|
1205 |
"sha256:03490be0e7b51a0c8073f877bec347eff31003f64f57d9518d419d9369452837",
|
|
|
1405 |
"sha256:4c586de507202505346f3e32d1363eb9ed6932f0c2f63184dea88983ff4971e2",
|
1406 |
"sha256:d2bbd99c320a2532ac71ff6a3164867884357da3e3301f0240090c5d2fdac7ec"
|
1407 |
],
|
1408 |
+
"markers": "python_full_version >= '3.6.3' and python_full_version < '4.0.0'",
|
1409 |
"version": "==12.4.4"
|
1410 |
},
|
1411 |
"semver": {
|
|
|
1554 |
"sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708",
|
1555 |
"sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"
|
1556 |
],
|
1557 |
+
"markers": "python_version >= '3.7'",
|
1558 |
"version": "==4.2.0"
|
1559 |
},
|
1560 |
"tzdata": {
|
|
|
1578 |
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
|
1579 |
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
|
1580 |
],
|
1581 |
+
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'",
|
1582 |
"version": "==1.26.9"
|
1583 |
},
|
1584 |
"validators": {
|
|
|
1692 |
"sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad",
|
1693 |
"sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"
|
1694 |
],
|
1695 |
+
"markers": "python_version >= '3.7'",
|
1696 |
"version": "==3.8.0"
|
1697 |
}
|
1698 |
},
|
|
|
1950 |
"sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708",
|
1951 |
"sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"
|
1952 |
],
|
1953 |
+
"markers": "python_version >= '3.7'",
|
1954 |
"version": "==4.2.0"
|
1955 |
}
|
1956 |
}
|
README.md
CHANGED
@@ -49,8 +49,13 @@ input to one GitHub public repo's URL(input)
|
|
49 |
- [x] Visualize a basic `networkx` graph using `pyvis`
|
50 |
- [x] Build a `streamlit` app
|
51 |
- [ ] Performance optimization
|
52 |
-
- [x] `requests` to `aiohttp
|
|
|
|
|
|
|
|
|
53 |
## References
|
54 |
|
55 |
- [How to set up a perfect Python project](https://sourcery.ai/blog/python-best-practices/)
|
56 |
-
- [Benchmark of popular graph/network packages](https://www.timlrx.com/blog/benchmark-of-popular-graph-network-packages)
|
|
|
|
49 |
- [x] Visualize a basic `networkx` graph using `pyvis`
|
50 |
- [x] Build a `streamlit` app
|
51 |
- [ ] Performance optimization
|
52 |
+
- [x] `requests` to `aiohttp`
|
53 |
+
- [x] change fetching GitHub repository content api from preventing querying multiple times
|
54 |
+
- [ ] ...
|
55 |
+
- [ ] Network analysis
|
56 |
+
- [ ] Enhance network visualization UI
|
57 |
## References
|
58 |
|
59 |
- [How to set up a perfect Python project](https://sourcery.ai/blog/python-best-practices/)
|
60 |
+
- [Benchmark of popular graph/network packages](https://www.timlrx.com/blog/benchmark-of-popular-graph-network-packages)
|
61 |
+
- [Asynchronous HTTP Requests in Python with aiohttp and asyncio](https://www.twilio.com/blog/asynchronous-http-requests-in-python-with-aiohttp)
|
app.py
CHANGED
@@ -22,19 +22,16 @@ st.markdown(
|
|
22 |
|
23 |
owner = st.text_input("Fill in the GitHub username", value="cyyeh")
|
24 |
repo = st.text_input("Fill in the GitHib repository", value="py-code-analyzer")
|
25 |
-
|
26 |
-
"Fill in
|
27 |
)
|
28 |
-
|
29 |
-
"Fill in the name of the commit/branch/tag. Default: the repository's default branch",
|
30 |
-
)
|
31 |
-
clicked_ok_button = st.button("OK")
|
32 |
st.markdown("---")
|
33 |
|
34 |
|
35 |
@conditonal_decorator(time_function, DEV)
|
36 |
-
def get_python_files(owner, repo,
|
37 |
-
return CodeFetcher().get_python_files(owner, repo,
|
38 |
|
39 |
|
40 |
@conditonal_decorator(time_function, DEV)
|
@@ -56,13 +53,13 @@ def read_graph_visualization_file():
|
|
56 |
|
57 |
if clicked_ok_button and owner and repo:
|
58 |
with st.spinner("Getting python files..."):
|
59 |
-
python_files = get_python_files(owner, repo,
|
60 |
|
61 |
with st.spinner("Parsing python files and generating imports graph..."):
|
62 |
imports_graph = generate_imports_graph(python_files)
|
63 |
|
64 |
with st.spinner("Generating graph visualization file..."):
|
65 |
-
generate_graph_visualization_file(imports_graph, f"{owner}/{repo}
|
66 |
|
67 |
with st.spinner("Showing the graph..."):
|
68 |
graph_visualization_file = read_graph_visualization_file()
|
|
|
22 |
|
23 |
owner = st.text_input("Fill in the GitHub username", value="cyyeh")
|
24 |
repo = st.text_input("Fill in the GitHib repository", value="py-code-analyzer")
|
25 |
+
tree_sha = st.text_input(
|
26 |
+
"Fill in sha, ex: 2f387d0adea72a7b4c99a5e8fc3e4fd83b5469b8",
|
27 |
)
|
28 |
+
clicked_ok_button = st.button("OK", disabled=not owner or not repo or not tree_sha)
|
|
|
|
|
|
|
29 |
st.markdown("---")
|
30 |
|
31 |
|
32 |
@conditonal_decorator(time_function, DEV)
|
33 |
+
def get_python_files(owner, repo, tree_sha):
|
34 |
+
return CodeFetcher().get_python_files(owner, repo, tree_sha)
|
35 |
|
36 |
|
37 |
@conditonal_decorator(time_function, DEV)
|
|
|
53 |
|
54 |
if clicked_ok_button and owner and repo:
|
55 |
with st.spinner("Getting python files..."):
|
56 |
+
python_files = get_python_files(owner, repo, tree_sha)
|
57 |
|
58 |
with st.spinner("Parsing python files and generating imports graph..."):
|
59 |
imports_graph = generate_imports_graph(python_files)
|
60 |
|
61 |
with st.spinner("Generating graph visualization file..."):
|
62 |
+
generate_graph_visualization_file(imports_graph, f"{owner}/{repo}")
|
63 |
|
64 |
with st.spinner("Showing the graph..."):
|
65 |
graph_visualization_file = read_graph_visualization_file()
|
py_code_analyzer/code_fetcher.py
CHANGED
@@ -1,14 +1,24 @@
|
|
1 |
"""CodeFetcher deals with every detail of
|
2 |
how to get all python files in the given directory
|
3 |
"""
|
4 |
-
import os
|
5 |
-
|
6 |
import requests
|
7 |
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
|
14 |
class CodeFetcher:
|
@@ -17,36 +27,29 @@ class CodeFetcher:
|
|
17 |
cls,
|
18 |
owner: str,
|
19 |
repo: str,
|
20 |
-
|
21 |
-
ref: str = "",
|
22 |
recursive: bool = True,
|
23 |
):
|
24 |
-
"""https://docs.github.com/en/rest/
|
|
|
25 |
|
26 |
-
api_url = (
|
27 |
-
f"https://api.github.com/repos/{owner}/{repo}/contents/{path}"
|
28 |
-
if not USER or not PERSONAL_ACCESS_TOKEN
|
29 |
-
else f"https://{USER}:{PERSONAL_ACCESS_TOKEN}@api.github.com/repos/{owner}/{repo}/contents/{path}"
|
30 |
-
)
|
31 |
-
if ref:
|
32 |
-
api_url += f"?ref={ref}"
|
33 |
|
34 |
-
|
35 |
-
api_results = requests.get(
|
36 |
api_url, headers={"Accept": "application/vnd.github.v3+json"}
|
37 |
-
)
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
return
|
|
|
1 |
"""CodeFetcher deals with every detail of
|
2 |
how to get all python files in the given directory
|
3 |
"""
|
|
|
|
|
4 |
import requests
|
5 |
|
6 |
+
|
7 |
+
def construct_api_url(owner, repo, tree_sha, recursive):
|
8 |
+
import os
|
9 |
+
|
10 |
+
# to increase api rate limiting
|
11 |
+
# https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
|
12 |
+
USER = os.environ.get("USER", "")
|
13 |
+
PERSONAL_ACCESS_TOKEN = os.environ.get("PERSONAL_ACCESS_TOKEN", "")
|
14 |
+
|
15 |
+
api_url = f"api.github.com/repos/{owner}/{repo}/git/trees/{tree_sha}"
|
16 |
+
if USER and PERSONAL_ACCESS_TOKEN:
|
17 |
+
api_url = f"{USER}:{PERSONAL_ACCESS_TOKEN}@{api_url}"
|
18 |
+
if recursive:
|
19 |
+
api_url += "?recursive=1"
|
20 |
+
|
21 |
+
return "https://" + api_url
|
22 |
|
23 |
|
24 |
class CodeFetcher:
|
|
|
27 |
cls,
|
28 |
owner: str,
|
29 |
repo: str,
|
30 |
+
tree_sha: str,
|
|
|
31 |
recursive: bool = True,
|
32 |
):
|
33 |
+
"""https://docs.github.com/en/rest/git/trees#get-a-tree"""
|
34 |
+
# TODO: deal with truncated api results
|
35 |
|
36 |
+
api_url = construct_api_url(owner, repo, tree_sha, recursive)
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
|
38 |
+
response = requests.get(
|
|
|
39 |
api_url, headers={"Accept": "application/vnd.github.v3+json"}
|
40 |
+
)
|
41 |
+
|
42 |
+
api_results = response.json()
|
43 |
+
if response.status_code == requests.codes.ok:
|
44 |
+
python_files = [
|
45 |
+
result
|
46 |
+
for result in api_results["tree"]
|
47 |
+
if type(result) is dict
|
48 |
+
and result["type"] == "blob"
|
49 |
+
and result["path"].endswith(".py")
|
50 |
+
]
|
51 |
+
return python_files
|
52 |
+
else:
|
53 |
+
print(api_results)
|
54 |
+
|
55 |
+
return []
|
py_code_analyzer/code_imports_analyzer.py
CHANGED
@@ -2,12 +2,44 @@
|
|
2 |
to get what modules are imported in given python files, then uses networkx to generate imports graph
|
3 |
"""
|
4 |
import ast
|
|
|
5 |
|
6 |
import aiohttp
|
|
|
7 |
|
8 |
from .graph_analyzer import GraphAnalyzer
|
9 |
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
class CodeImportsAnalyzer:
|
12 |
class _NodeVisitor(ast.NodeVisitor):
|
13 |
def __init__(self, imports):
|
@@ -35,21 +67,24 @@ class CodeImportsAnalyzer:
|
|
35 |
|
36 |
async def analyze(self):
|
37 |
async with aiohttp.ClientSession() as session:
|
|
|
38 |
for python_file in self.python_files:
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
|
|
|
|
53 |
|
54 |
def generate_imports_graph(self):
|
55 |
# TODO: thought on how to improve the graph generation logic
|
|
|
2 |
to get what modules are imported in given python files, then uses networkx to generate imports graph
|
3 |
"""
|
4 |
import ast
|
5 |
+
import asyncio
|
6 |
|
7 |
import aiohttp
|
8 |
+
import pybase64
|
9 |
|
10 |
from .graph_analyzer import GraphAnalyzer
|
11 |
|
12 |
|
13 |
+
def construct_api_url(api_url):
|
14 |
+
import os
|
15 |
+
|
16 |
+
# to increase api rate limiting
|
17 |
+
# https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
|
18 |
+
USER = os.environ.get("USER", "")
|
19 |
+
PERSONAL_ACCESS_TOKEN = os.environ.get("PERSONAL_ACCESS_TOKEN", "")
|
20 |
+
|
21 |
+
api_urls = api_url.split("://")
|
22 |
+
if USER and PERSONAL_ACCESS_TOKEN:
|
23 |
+
api_url = f"{USER}:{PERSONAL_ACCESS_TOKEN}@{api_urls[-1]}"
|
24 |
+
|
25 |
+
return f"{api_urls[0]}://{api_url}"
|
26 |
+
|
27 |
+
|
28 |
+
async def get_program_text(session, python_file):
|
29 |
+
async with session.get(
|
30 |
+
construct_api_url(python_file["url"]),
|
31 |
+
headers={"Accept": "application/vnd.github.v3+json"},
|
32 |
+
) as response:
|
33 |
+
data = await response.json()
|
34 |
+
print(data)
|
35 |
+
if data["encoding"] == "base64":
|
36 |
+
return data["content"]
|
37 |
+
else:
|
38 |
+
print(
|
39 |
+
f"WARNING: {python_file}'s encoding is {data['encoding']}, not base64"
|
40 |
+
)
|
41 |
+
|
42 |
+
|
43 |
class CodeImportsAnalyzer:
|
44 |
class _NodeVisitor(ast.NodeVisitor):
|
45 |
def __init__(self, imports):
|
|
|
67 |
|
68 |
async def analyze(self):
|
69 |
async with aiohttp.ClientSession() as session:
|
70 |
+
tasks = []
|
71 |
for python_file in self.python_files:
|
72 |
+
self.python_imports += [
|
73 |
+
{
|
74 |
+
"file_name": python_file["path"].split("/")[-1],
|
75 |
+
"file_path": python_file["path"],
|
76 |
+
"imports": [],
|
77 |
+
}
|
78 |
+
]
|
79 |
+
tasks.append(
|
80 |
+
asyncio.ensure_future(get_program_text(session, python_file))
|
81 |
+
)
|
82 |
+
|
83 |
+
base64_program_texts = await asyncio.gather(*tasks)
|
84 |
+
for base64_program_text in base64_program_texts:
|
85 |
+
program = pybase64.b64decode(base64_program_text)
|
86 |
+
tree = ast.parse(program)
|
87 |
+
self._node_visitor.visit(tree)
|
88 |
|
89 |
def generate_imports_graph(self):
|
90 |
# TODO: thought on how to improve the graph generation logic
|