github.com/pachyderm/pachyderm@v1.13.4/etc/testing/introspect/introspect.ipynb (about) 1 { 2 "cells": [ 3 { 4 "cell_type": "code", 5 "execution_count": 415, 6 "metadata": {}, 7 "outputs": [], 8 "source": [ 9 "from circleci.api import Api\n", 10 "import pprint\n", 11 "from collections import defaultdict\n", 12 "\n", 13 "token = open(\".env\").readlines()[0].split(\"=\")[1].strip()\n", 14 "circleci = Api(token)\n", 15 "\n", 16 "# get info about your user\n", 17 "#pprint.pprint(circleci.get_user_info())\n", 18 "\n", 19 "# get list of all of your projects\n", 20 "# --> build_num --> get_build_info() -> steps -> output_url -> fetch it -> x[0][\"message\"] is newline delim string\n", 21 "# --> .outcome == \"failed\" e.g.\n", 22 "\n", 23 "results = defaultdict(lambda: defaultdict(int))\n", 24 "\n", 25 "# get results 100 at a time\n", 26 "\n", 27 "get_how_many = 32\n", 28 "per_page = 100\n", 29 "pages = max(1, int(get_how_many / per_page))\n", 30 "builds = []\n", 31 "\n", 32 "for i in range(pages):\n", 33 " for build in circleci.get_project_build_summary(\n", 34 " \"pachyderm\", \"pachyderm\", limit=min(100, get_how_many), offset=i*per_page,\n", 35 " ):\n", 36 " builds.append(build)\n", 37 " outcome = build[\"outcome\"]\n", 38 " build_num = build[\"build_num\"]\n", 39 "\n", 40 " if not outcome == \"failed\" and not outcome == \"success\":\n", 41 " continue\n", 42 "\n", 43 " job = build[\"workflows\"][\"job_name\"]\n", 44 " #print(f\"build {build_num} {outcome} {job}\")\n", 45 " if job.startswith(\"test-\"):\n", 46 " results[job][outcome] += 1\n", 47 "\n", 48 "#builds = builds[:12]" 49 ] 50 }, 51 { 52 "cell_type": "markdown", 53 "metadata": {}, 54 "source": [ 55 "# Finding flakiest test suites\n", 56 "\n", 57 "The following produces a table of test suites ordered by flakiest suite first." 58 ] 59 }, 60 { 61 "cell_type": "code", 62 "execution_count": 416, 63 "metadata": {}, 64 "outputs": [ 65 { 66 "data": { 67 "text/html": [ 68 "<div>\n", 69 "<style scoped>\n", 70 " .dataframe tbody tr th:only-of-type {\n", 71 " vertical-align: middle;\n", 72 " }\n", 73 "\n", 74 " .dataframe tbody tr th {\n", 75 " vertical-align: top;\n", 76 " }\n", 77 "\n", 78 " .dataframe thead th {\n", 79 " text-align: right;\n", 80 " }\n", 81 "</style>\n", 82 "<table border=\"1\" class=\"dataframe\">\n", 83 " <thead>\n", 84 " <tr style=\"text-align: right;\">\n", 85 " <th></th>\n", 86 " <th>failed</th>\n", 87 " <th>success</th>\n", 88 " <th>pass_rate</th>\n", 89 " </tr>\n", 90 " </thead>\n", 91 " <tbody>\n", 92 " <tr>\n", 93 " <th>test-MISC</th>\n", 94 " <td>1.0</td>\n", 95 " <td>1.0</td>\n", 96 " <td>0.5</td>\n", 97 " </tr>\n", 98 " <tr>\n", 99 " <th>test-PFS</th>\n", 100 " <td>1.0</td>\n", 101 " <td>1.0</td>\n", 102 " <td>0.5</td>\n", 103 " </tr>\n", 104 " <tr>\n", 105 " <th>test-PPS4</th>\n", 106 " <td>1.0</td>\n", 107 " <td>1.0</td>\n", 108 " <td>0.5</td>\n", 109 " </tr>\n", 110 " <tr>\n", 111 " <th>test-PPS2</th>\n", 112 " <td>0.0</td>\n", 113 " <td>2.0</td>\n", 114 " <td>1.0</td>\n", 115 " </tr>\n", 116 " <tr>\n", 117 " <th>test-PPS3</th>\n", 118 " <td>0.0</td>\n", 119 " <td>1.0</td>\n", 120 " <td>1.0</td>\n", 121 " </tr>\n", 122 " <tr>\n", 123 " <th>test-PPS5</th>\n", 124 " <td>0.0</td>\n", 125 " <td>2.0</td>\n", 126 " <td>1.0</td>\n", 127 " </tr>\n", 128 " <tr>\n", 129 " <th>test-PPS1</th>\n", 130 " <td>0.0</td>\n", 131 " <td>2.0</td>\n", 132 " <td>1.0</td>\n", 133 " </tr>\n", 134 " <tr>\n", 135 " <th>test-ADMIN</th>\n", 136 " <td>0.0</td>\n", 137 " <td>2.0</td>\n", 138 " <td>1.0</td>\n", 139 " </tr>\n", 140 " <tr>\n", 141 " <th>test-EXAMPLES</th>\n", 142 " <td>0.0</td>\n", 143 " <td>2.0</td>\n", 144 " <td>1.0</td>\n", 145 " </tr>\n", 146 " <tr>\n", 147 " <th>test-AUTH1</th>\n", 148 " <td>0.0</td>\n", 149 " <td>2.0</td>\n", 150 " <td>1.0</td>\n", 151 " </tr>\n", 152 " <tr>\n", 153 " <th>test-PPS6</th>\n", 154 " <td>0.0</td>\n", 155 " <td>2.0</td>\n", 156 " <td>1.0</td>\n", 157 " </tr>\n", 158 " <tr>\n", 159 " <th>test-AUTH2</th>\n", 160 " <td>0.0</td>\n", 161 " <td>1.0</td>\n", 162 " <td>1.0</td>\n", 163 " </tr>\n", 164 " </tbody>\n", 165 "</table>\n", 166 "</div>" 167 ], 168 "text/plain": [ 169 " failed success pass_rate\n", 170 "test-MISC 1.0 1.0 0.5\n", 171 "test-PFS 1.0 1.0 0.5\n", 172 "test-PPS4 1.0 1.0 0.5\n", 173 "test-PPS2 0.0 2.0 1.0\n", 174 "test-PPS3 0.0 1.0 1.0\n", 175 "test-PPS5 0.0 2.0 1.0\n", 176 "test-PPS1 0.0 2.0 1.0\n", 177 "test-ADMIN 0.0 2.0 1.0\n", 178 "test-EXAMPLES 0.0 2.0 1.0\n", 179 "test-AUTH1 0.0 2.0 1.0\n", 180 "test-PPS6 0.0 2.0 1.0\n", 181 "test-AUTH2 0.0 1.0 1.0" 182 ] 183 }, 184 "execution_count": 416, 185 "metadata": {}, 186 "output_type": "execute_result" 187 } 188 ], 189 "source": [ 190 "import pandas as pd\n", 191 "df = pd.DataFrame.from_dict(results)\n", 192 "\n", 193 "# Transpose\n", 194 "df = df.T\n", 195 "\n", 196 "# NaN -> 0\n", 197 "df = df.fillna(0)\n", 198 "\n", 199 "df['pass_rate'] = df['success'] / (df['failed'] + df['success'])\n", 200 "\n", 201 "# sort by failed\n", 202 "df = df.sort_values(by=[\"pass_rate\"])\n", 203 "\n", 204 "df" 205 ] 206 }, 207 { 208 "cell_type": "markdown", 209 "metadata": {}, 210 "source": [ 211 "# Finding flakiest individual tests\n", 212 "Now we fetch the logs for each individual test and find the flakiest individual tests." 213 ] 214 }, 215 { 216 "cell_type": "code", 217 "execution_count": 417, 218 "metadata": {}, 219 "outputs": [], 220 "source": [ 221 "import requests\n", 222 "cache = {}\n", 223 "build_info_cache = {}" 224 ] 225 }, 226 { 227 "cell_type": "code", 228 "execution_count": 418, 229 "metadata": {}, 230 "outputs": [], 231 "source": [ 232 "build_map = {}" 233 ] 234 }, 235 { 236 "cell_type": "code", 237 "execution_count": 419, 238 "metadata": {}, 239 "outputs": [], 240 "source": [ 241 "def parse_build(build):\n", 242 " tests = []\n", 243 " failed = set()\n", 244 " passed = set()\n", 245 " skipped = set()\n", 246 " try:\n", 247 " output_url = build[\"steps\"][5][\"actions\"][0][\"output_url\"]\n", 248 " except Exception as e:\n", 249 " print(f\"Got error: {e}, continuing...\")\n", 250 " return set(), set(), set()\n", 251 " \n", 252 " if output_url in cache:\n", 253 " lines = cache[output_url]\n", 254 " else:\n", 255 " lines = requests.get(output_url).json()\n", 256 " cache[output_url] = lines\n", 257 "\n", 258 " for line in lines[0][\"message\"].split(\"\\n\"):\n", 259 " #print(line)\n", 260 " if \"RUN\" in line:\n", 261 " parts = line.split(\"RUN\")\n", 262 " if len(parts) != 2:\n", 263 " continue\n", 264 " preamble, test = parts\n", 265 " test = test.strip()\n", 266 " # ignore docker RUN lines which contain e.g. \"#10\"\n", 267 " if \"#\" in preamble or \"Step\" in preamble:\n", 268 " continue\n", 269 " if len(test) > 100:\n", 270 " # some base64 gunk\n", 271 " continue\n", 272 " if \"AcceptEnv\" in test or \"cd pachyderm\" in test \\\n", 273 " or \"git clone\" in test or \"NING\" in test or \"_BAD_TESTS\" in test:\n", 274 " continue\n", 275 " tests.append(test)\n", 276 " if \"FAIL\" in line:\n", 277 " test = line.split(\"FAIL\")[1].replace(\":\", \"\").strip().split(\"(\")[0].strip()\n", 278 " if \"github.com\" in test or test == \"\":\n", 279 " # filter out some more noise\n", 280 " continue\n", 281 " if len(test) > 100:\n", 282 " # some base64 gunk\n", 283 " continue\n", 284 " failed.add(test)\n", 285 " if \"PASS\" in line:\n", 286 " test = line.split(\"PASS\")[1].replace(\":\", \"\").strip().split(\"(\")[0].strip()\n", 287 " if test == \"\":\n", 288 " # This happens when all the tests pass, we get a \"PASS\" on its own.\n", 289 " continue\n", 290 " if len(test) > 100:\n", 291 " # some base64 gunk\n", 292 " continue\n", 293 " if \"\\\\n\" in test:\n", 294 " continue\n", 295 " passed.add(test)\n", 296 " if \"SKIP\" in line:\n", 297 " test = line.split(\"SKIP\")[1].replace(\":\", \"\").strip().split(\"(\")[0].strip()\n", 298 " if test == \"\":\n", 299 " # This happens when all the tests pass, we get a \"PASS\" on its own.\n", 300 " continue\n", 301 " if len(test) > 100:\n", 302 " # some base64 gunk\n", 303 " continue\n", 304 " if \"\\\\n\" in test:\n", 305 " continue\n", 306 " skipped.add(test)\n", 307 "\n", 308 " all_tests = set(tests)\n", 309 " for test in all_tests:\n", 310 " if test not in build_map:\n", 311 " build_map[test] = build[\"workflows\"][\"job_name\"], \\\n", 312 " f\"<a target='_blank' href='{build['build_url']}'>{build['build_num']}</a>\"\n", 313 " hung = all_tests - failed - passed - skipped\n", 314 " assert all_tests == (failed | passed | hung | skipped), \\\n", 315 " f\"all={all_tests}, failed={failed}, passed={passed}, hung={hung}, skipped={skipped}\"\n", 316 " return passed, failed, hung" 317 ] 318 }, 319 { 320 "cell_type": "code", 321 "execution_count": 420, 322 "metadata": {}, 323 "outputs": [ 324 { 325 "name": "stdout", 326 "output_type": "stream", 327 "text": [ 328 ".Got error: list index out of range, continuing...\n", 329 ".Got error: list index out of range, continuing...\n", 330 ".Got error: list index out of range, continuing...\n", 331 ".Got error: list index out of range, continuing...\n", 332 ".Got error: list index out of range, continuing...\n", 333 ".Got error: list index out of range, continuing...\n", 334 ".Got error: list index out of range, continuing...\n", 335 ".Got error: list index out of range, continuing...\n", 336 ".Got error: list index out of range, continuing...\n", 337 ".Got error: list index out of range, continuing...\n", 338 "......................" 339 ] 340 } 341 ], 342 "source": [ 343 "build_results = defaultdict(lambda: defaultdict(int))\n", 344 "\n", 345 "for build in builds:\n", 346 " print(\".\", end=\"\")\n", 347 " if build[\"build_num\"] in build_info_cache:\n", 348 " build_info = build_info_cache[build[\"build_num\"]]\n", 349 " else:\n", 350 " build_info = circleci.get_build_info(\"pachyderm\", \"pachyderm\", build[\"build_num\"])\n", 351 " build_info_cache[build[\"build_num\"]] = build_info\n", 352 " passed, failed, hung = parse_build(build_info)\n", 353 " for b in passed:\n", 354 " build_results[b][\"pass\"] += 1\n", 355 " build_results[b][\"bucket\"] = build_map[b][0]\n", 356 " for b in failed:\n", 357 " build_results[b][\"fail\"] += 1\n", 358 " build_results[b][\"bucket\"] = build_map[b][0]\n", 359 " build_results[b][\"example\"] = build_map[b][1]\n", 360 " for b in hung:\n", 361 " build_results[b][\"hung\"] += 1\n", 362 " build_results[b][\"bucket\"] = build_map[b][0]\n", 363 " build_results[b][\"example\"] = build_map[b][1]" 364 ] 365 }, 366 { 367 "cell_type": "code", 368 "execution_count": 421, 369 "metadata": {}, 370 "outputs": [ 371 { 372 "ename": "KeyError", 373 "evalue": "'fail'", 374 "output_type": "error", 375 "traceback": [ 376 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 377 "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", 378 "\u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2888\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2889\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2890\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 379 "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", 380 "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", 381 "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", 382 "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", 383 "\u001b[0;31mKeyError\u001b[0m: 'fail'", 384 "\nThe above exception was the direct cause of the following exception:\n", 385 "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", 386 "\u001b[0;32m<ipython-input-421-d2968774b94e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0mdf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfillna\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'hang_rate'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'hung'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'pass'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'fail'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'hung'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 11\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'fail_rate'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'fail'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'pass'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'fail'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'hung'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'hang_or_fail'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'hang_rate'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'fail_rate'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 387 "\u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 2897\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2898\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2899\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2900\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2901\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 388 "\u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2889\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2890\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2891\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2892\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2893\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mtolerance\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 389 "\u001b[0;31mKeyError\u001b[0m: 'fail'" 390 ] 391 } 392 ], 393 "source": [ 394 "import pandas as pd\n", 395 "df = pd.DataFrame.from_dict(build_results)\n", 396 "\n", 397 "# Transpose\n", 398 "df = df.T\n", 399 "\n", 400 "# NaN -> 0\n", 401 "df = df.fillna(0)\n", 402 "\n", 403 "df['hang_rate'] = df['hung'] / (df['pass'] + df['fail'] + df['hung'])\n", 404 "df['fail_rate'] = df['fail'] / (df['pass'] + df['fail'] + df['hung'])\n", 405 "df['hang_or_fail'] = df['hang_rate'] + df['fail_rate']\n", 406 "\n", 407 "hangy = df[df[\"hang_rate\"] > 0]\n", 408 "faily = df[df[\"fail_rate\"] > 0]\n", 409 "\n", 410 "# sort by failed\n", 411 "hangy = hangy.sort_values(by=[\"hang_rate\"], ascending=False)\n", 412 "faily = hangy.sort_values(by=[\"fail_rate\"], ascending=False)\n", 413 "\n", 414 "bad = df[df[\"hang_or_fail\"] > 0]\n", 415 "bad = bad.sort_values(by=[\"hang_or_fail\"], ascending=False)" 416 ] 417 }, 418 { 419 "cell_type": "code", 420 "execution_count": null, 421 "metadata": {}, 422 "outputs": [], 423 "source": [ 424 "pandas.set_option('display.max_rows', None)" 425 ] 426 }, 427 { 428 "cell_type": "code", 429 "execution_count": null, 430 "metadata": {}, 431 "outputs": [], 432 "source": [ 433 "from IPython.display import HTML\n", 434 "HTML(bad.to_html(escape=False))" 435 ] 436 }, 437 { 438 "cell_type": "code", 439 "execution_count": null, 440 "metadata": {}, 441 "outputs": [], 442 "source": [] 443 } 444 ], 445 "metadata": { 446 "kernelspec": { 447 "display_name": "Python 3", 448 "language": "python", 449 "name": "python3" 450 }, 451 "language_info": { 452 "codemirror_mode": { 453 "name": "ipython", 454 "version": 3 455 }, 456 "file_extension": ".py", 457 "mimetype": "text/x-python", 458 "name": "python", 459 "nbconvert_exporter": "python", 460 "pygments_lexer": "ipython3", 461 "version": "3.8.5" 462 } 463 }, 464 "nbformat": 4, 465 "nbformat_minor": 4 466 }