deprecated some constructor arguments

This commit is contained in:
Abubakar Abid 2021-12-25 07:37:46 -06:00
commit 40adb8537b
14 changed files with 497 additions and 238 deletions

2
.gitignore vendored
View File

@ -20,7 +20,7 @@ gradio/templates/frontend/static
*.db
*.sqlite3
gradio/launches.json
flagged
flagged/*
# Tests
.coverage

View File

@ -1,7 +1,7 @@
{
"name": "gradio",
"version": "1.0.0",
"lockfileVersion": 2,
"lockfileVersion": 1,
"requires": true,
"packages": {
"": {
@ -25990,13 +25990,13 @@
"acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"requires": {}
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="
},
"acorn-node": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
"integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
"dev": true,
"requires": {
"acorn": "^7.0.0",
"acorn-walk": "^7.0.0",
@ -26054,14 +26054,12 @@
"ajv-errors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
"integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
"requires": {}
"integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ=="
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"requires": {}
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
},
"alphanum-sort": {
"version": "1.0.2",
@ -26152,7 +26150,8 @@
"arg": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz",
"integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA=="
"integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==",
"dev": true
},
"argparse": {
"version": "1.0.10",
@ -26530,8 +26529,7 @@
"babel-plugin-named-asset-import": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz",
"integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==",
"requires": {}
"integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw=="
},
"babel-plugin-polyfill-corejs2": {
"version": "0.2.0",
@ -26915,6 +26913,15 @@
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -27257,7 +27264,8 @@
"camelcase-css": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
"dev": true
},
"camelcase-keys": {
"version": "6.2.2",
@ -28114,7 +28122,8 @@
"css-unit-converter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==",
"dev": true
},
"css-what": {
"version": "3.4.2",
@ -28498,7 +28507,8 @@
"defined": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
"integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
"integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
"dev": true
},
"del": {
"version": "4.1.1",
@ -28630,6 +28640,7 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz",
"integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==",
"dev": true,
"requires": {
"acorn-node": "^1.6.1",
"defined": "^1.0.0",
@ -28639,7 +28650,8 @@
"didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
"dev": true
},
"diff-sequences": {
"version": "26.6.2",
@ -29213,8 +29225,7 @@
"eslint-config-prettier": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz",
"integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==",
"requires": {}
"integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew=="
},
"eslint-config-react-app": {
"version": "6.0.0",
@ -29400,8 +29411,7 @@
"eslint-plugin-react-hooks": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
"requires": {}
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ=="
},
"eslint-plugin-testing-library": {
"version": "3.10.2",
@ -30223,6 +30233,12 @@
}
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
"filelist": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
@ -31159,7 +31175,8 @@
"html-tags": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg=="
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
"dev": true
},
"html-webpack-plugin": {
"version": "4.5.0",
@ -32435,8 +32452,7 @@
"jest-pnp-resolver": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
"requires": {}
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w=="
},
"jest-regex-util": {
"version": "26.0.0",
@ -33018,7 +33034,8 @@
"lilconfig": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz",
"integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA=="
"integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==",
"dev": true
},
"lines-and-columns": {
"version": "1.1.6",
@ -33150,7 +33167,8 @@
"lodash.topath": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz",
"integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak="
"integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak=",
"dev": true
},
"lodash.truncate": {
"version": "4.4.2",
@ -33616,7 +33634,8 @@
"modern-normalize": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz",
"integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA=="
"integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==",
"dev": true
},
"move-concurrently": {
"version": "1.0.1",
@ -33740,6 +33759,7 @@
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
"integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==",
"dev": true,
"requires": {
"lodash": "^4.17.21"
}
@ -34009,7 +34029,8 @@
"object-hash": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
"dev": true
},
"object-inspect": {
"version": "1.9.0",
@ -34413,7 +34434,8 @@
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
},
"picomatch": {
"version": "2.2.2",
@ -34913,6 +34935,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz",
"integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=",
"dev": true,
"requires": {
"glob": "^7.1.2",
"object-assign": "^4.1.1",
@ -34924,6 +34947,7 @@
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
@ -34932,6 +34956,7 @@
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@ -34942,6 +34967,7 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@ -34949,22 +34975,26 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"postcss": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
"dev": true,
"requires": {
"chalk": "^2.4.1",
"source-map": "^0.6.1",
@ -34974,12 +35004,14 @@
"postcss-value-parser": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
@ -35016,6 +35048,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz",
"integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==",
"dev": true,
"requires": {
"camelcase-css": "^2.0.1",
"postcss": "^7.0.18"
@ -35294,6 +35327,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.3.tgz",
"integrity": "sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==",
"dev": true,
"requires": {
"postcss": "^7.0.32",
"postcss-selector-parser": "^6.0.2"
@ -36485,7 +36519,8 @@
"pretty-hrtime": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
"integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
"integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
"dev": true
},
"process": {
"version": "0.11.10",
@ -36619,6 +36654,7 @@
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.1.3.tgz",
"integrity": "sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw==",
"dev": true,
"requires": {
"commander": "^8.0.0",
"glob": "^7.1.7",
@ -36629,12 +36665,14 @@
"commander": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
"dev": true
},
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@ -36647,12 +36685,14 @@
"nanoid": {
"version": "3.1.30",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==",
"dev": true
},
"postcss": {
"version": "8.4.5",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
"integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
"dev": true,
"requires": {
"nanoid": "^3.1.30",
"picocolors": "^1.0.0",
@ -36663,6 +36703,7 @@
"version": "6.0.7",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz",
"integrity": "sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==",
"dev": true,
"requires": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@ -36712,7 +36753,8 @@
"quick-lru": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
"dev": true
},
"raf": {
"version": "3.4.1",
@ -36800,8 +36842,7 @@
"react-chartjs-2": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-3.3.0.tgz",
"integrity": "sha512-4Mt0SR2aiUbWi/4762odRBYSnbNKSs4HWc0o3IW43py5bMfmfpeZU95w6mbvtuLZH/M3GsPJMU8DvDc+5U9blQ==",
"requires": {}
"integrity": "sha512-4Mt0SR2aiUbWi/4762odRBYSnbNKSs4HWc0o3IW43py5bMfmfpeZU95w6mbvtuLZH/M3GsPJMU8DvDc+5U9blQ=="
},
"react-cropper": {
"version": "2.1.8",
@ -37073,8 +37114,7 @@
"react-webcam": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/react-webcam/-/react-webcam-5.2.3.tgz",
"integrity": "sha512-7rBh4Veeumpy45ObkZCsG6zezaamkwK5Iqxc0AFhX2ZzWQZXZ+f61yJ1yIb9Y62U4d7KkfP/xEduBCRzzcN4Dw==",
"requires": {}
"integrity": "sha512-7rBh4Veeumpy45ObkZCsG6zezaamkwK5Iqxc0AFhX2ZzWQZXZ+f61yJ1yIb9Y62U4d7KkfP/xEduBCRzzcN4Dw=="
},
"read-pkg": {
"version": "2.0.0",
@ -37202,6 +37242,7 @@
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
"dev": true,
"requires": {
"css-unit-converter": "^1.1.1",
"postcss-value-parser": "^3.3.0"
@ -37210,7 +37251,8 @@
"postcss-value-parser": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
"dev": true
}
}
},
@ -38691,7 +38733,8 @@
"source-map-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz",
"integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA=="
"integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==",
"dev": true
},
"source-map-resolve": {
"version": "0.6.0",
@ -38997,21 +39040,6 @@
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
},
"dependencies": {
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
}
}
},
"string-length": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@ -39075,6 +39103,21 @@
"define-properties": "^1.1.3"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
},
"dependencies": {
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
}
}
},
"stringify-object": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
@ -39294,6 +39337,7 @@
"version": "npm:@tailwindcss/postcss7-compat@2.2.17",
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss7-compat/-/postcss7-compat-2.2.17.tgz",
"integrity": "sha512-3h2svqQAqYHxRZ1KjsJjZOVTQ04m29LjfrLjXyZZEJuvUuJN+BCIF9GI8vhE1s0plS0mogd6E6YLg6mu4Wv/Vw==",
"dev": true,
"requires": {
"arg": "^5.0.1",
"autoprefixer": "^9",
@ -39336,6 +39380,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@ -39345,6 +39390,7 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
"dev": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@ -39360,6 +39406,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
@ -39370,6 +39417,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/color/-/color-4.1.0.tgz",
"integrity": "sha512-o2rkkxyLGgYoeUy1OodXpbPAQNmlNBrirQ8ODO8QutzDiDMNdezSOZLNnusQ6pUpCQJUsaJIo9DZJKqa2HgH7A==",
"dev": true,
"requires": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
@ -39379,6 +39427,7 @@
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz",
"integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==",
"dev": true,
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
@ -39388,6 +39437,7 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
"integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
"dev": true,
"requires": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1",
@ -39400,6 +39450,7 @@
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@ -39412,6 +39463,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
@ -39422,6 +39474,7 @@
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
"integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@ -39432,6 +39485,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"requires": {
"is-glob": "^4.0.3"
},
@ -39440,6 +39494,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
@ -39450,6 +39505,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz",
"integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==",
"dev": true,
"requires": {
"import-from": "^3.0.0"
}
@ -39458,6 +39514,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz",
"integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==",
"dev": true,
"requires": {
"resolve-from": "^5.0.0"
}
@ -39466,6 +39523,7 @@
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
"dev": true,
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.2.3"
@ -39474,7 +39532,8 @@
"picomatch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
"dev": true
}
}
},
@ -39482,6 +39541,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz",
"integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==",
"dev": true,
"requires": {
"import-cwd": "^3.0.0",
"lilconfig": "^2.0.3",
@ -39492,6 +39552,7 @@
"version": "6.0.7",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz",
"integrity": "sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==",
"dev": true,
"requires": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@ -39501,6 +39562,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"requires": {
"picomatch": "^2.2.1"
}
@ -39509,6 +39571,7 @@
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
"dev": true,
"requires": {
"is-core-module": "^2.2.0",
"path-parse": "^1.0.6"
@ -39777,6 +39840,7 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
"dev": true,
"requires": {
"rimraf": "^3.0.0"
}
@ -41311,14 +41375,6 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
@ -41344,6 +41400,14 @@
}
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
@ -41869,8 +41933,7 @@
"ws": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==",
"requires": {}
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
},
"xml-name-validator": {
"version": "3.0.0",

View File

@ -1,6 +1,7 @@
from gradio.interface import * # This makes it possible to import `Interface` as `gradio.Interface`.
from gradio.networking import get_state, set_state
from gradio.mix import *
from gradio.flagging import *
import pkg_resources
current_pkg_version = pkg_resources.require("gradio")[0].version

248
gradio/flagging.py Normal file
View File

@ -0,0 +1,248 @@
import gradio as gr
import os
import datetime
from gradio import encryptor
import csv
import io
from abc import ABC, abstractmethod
class FlaggingCallback(ABC):
"""
An abstract class for defining the methods that any FlaggingCallback should have.
"""
@abstractmethod
def setup(self, flagging_dir):
"""
This method should be overridden and ensure that everything is set up correctly for flag().
This method gets called once at the beginning of the Interface.launch() method.
Parameters:
flagging_dir: A string, typically containing the path to the directory where the flagging file should be storied (provided as an argument to Interface.__init__()).
"""
pass
@abstractmethod
def flag(self, interface, input_data, output_data, flag_option=None, flag_index=None, username=None):
"""
This method should be overridden by the FlaggingCallback subclass and may contain optional additional arguments.
This gets called every time the <flag> button is pressed.
Parameters:
interface: The Interface object that is being used to launch the flagging interface.
input_data: The input data to be flagged.
output_data: The output data to be flagged.
flag_option (optional): In the case that flagging_options are provided, the flag option that is being used.
flag_index (optional): The index of the sample that is being flagged.
username (optional): The username of the user that is flagging the data, if logged in.
Returns:
(int) The total number of samples that have been flagged.
"""
pass
class SimpleCSVLogger(FlaggingCallback):
"""
A simple example implementation of the FlaggingCallback abstract class
provided for illustrative purposes.
"""
def setup(self, flagging_dir):
self.flagging_dir = flagging_dir
os.makedirs(flagging_dir, exist_ok=True)
def flag(self, interface, input_data, output_data, flag_option=None, flag_index=None, username=None):
flagging_dir = self.flagging_dir
log_filepath = "{}/log.csv".format(flagging_dir)
csv_data = []
for i, input in enumerate(interface.input_components):
csv_data.append(input.save_flagged(
flagging_dir, interface.config["input_components"][i]["label"], input_data[i], None))
for i, output in enumerate(interface.output_components):
csv_data.append(output.save_flagged(
flagging_dir, interface.config["output_components"][i]["label"], output_data[i], None) if
output_data[i] is not None else "")
with open(log_filepath, "a", newline="") as csvfile:
writer = csv.writer(csvfile)
writer.writerow(csv_data)
with open(log_filepath, "r") as csvfile:
line_count = len([None for row in csv.reader(csvfile)]) - 1
return line_count
class CSVLogger(FlaggingCallback):
"""
The default implementation of the FlaggingCallback abstract class.
Logs the input and output data to a CSV file.
"""
def setup(self, flagging_dir):
self.flagging_dir = flagging_dir
os.makedirs(flagging_dir, exist_ok=True)
def flag(self, interface, input_data, output_data, flag_option=None, flag_index=None, username=None):
flagging_dir = self.flagging_dir
log_fp = "{}/log.csv".format(flagging_dir)
encryption_key = interface.encryption_key if interface.encrypt else None
is_new = not os.path.exists(log_fp)
if flag_index is None:
csv_data = []
for i, input in enumerate(interface.input_components):
csv_data.append(input.save_flagged(
flagging_dir, interface.config["input_components"][i]["label"], input_data[i], encryption_key))
for i, output in enumerate(interface.output_components):
csv_data.append(output.save_flagged(
flagging_dir, interface.config["output_components"][i]["label"], output_data[i], encryption_key) if
output_data[i] is not None else "")
if flag_option is not None:
csv_data.append(flag_option)
if username is not None:
csv_data.append(username)
csv_data.append(str(datetime.datetime.now()))
if is_new:
headers = [interface["label"]
for interface in interface.config["input_components"]]
headers += [interface["label"]
for interface in interface.config["output_components"]]
if interface.flagging_options is not None:
headers.append("flag")
if username is not None:
headers.append("username")
headers.append("timestamp")
def replace_flag_at_index(file_content):
file_content = io.StringIO(file_content)
content = list(csv.reader(file_content))
header = content[0]
flag_col_index = header.index("flag")
content[flag_index][flag_col_index] = flag_option
output = io.StringIO()
writer = csv.writer(output)
writer.writerows(content)
return output.getvalue()
if interface.encrypt:
output = io.StringIO()
if not is_new:
with open(log_fp, "rb") as csvfile:
encrypted_csv = csvfile.read()
decrypted_csv = encryptor.decrypt(
interface.encryption_key, encrypted_csv)
file_content = decrypted_csv.decode()
if flag_index is not None:
file_content = replace_flag_at_index(file_content)
output.write(file_content)
writer = csv.writer(output)
if flag_index is None:
if is_new:
writer.writerow(headers)
writer.writerow(csv_data)
with open(log_fp, "wb") as csvfile:
csvfile.write(encryptor.encrypt(
interface.encryption_key, output.getvalue().encode()))
else:
if flag_index is None:
with open(log_fp, "a", newline="") as csvfile:
writer = csv.writer(csvfile)
if is_new:
writer.writerow(headers)
writer.writerow(csv_data)
else:
with open(log_fp) as csvfile:
file_content = csvfile.read()
file_content = replace_flag_at_index(file_content)
with open(log_fp, "w", newline="") as csvfile: # newline parameter needed for Windows
csvfile.write(file_content)
with open(log_fp, "r") as csvfile:
line_count = len([None for row in csv.reader(csvfile)]) - 1
return line_count
class HuggingFaceDatasetSaver(FlaggingCallback):
"""
A FlaggingCallback that saves flagged data to a HuggingFace dataset.
"""
def __init__(self, hf_foken, dataset_name, organization=None,
private=False, verbose=True):
"""
Params:
hf_token (str): The token to use to access the huggingface API.
dataset_name (str): The name of the dataset to save the data to, e.g.
"image-classifier-1"
organization (str): The name of the organization to which to attach
the datasets. If None, the dataset attaches to the user only.
private (bool): If the dataset does not already exist, whether it
should be created as a private dataset or public. Private datasets
may require paid huggingface.co accounts
verbose (bool): Whether to print out the status of the dataset
creation.
"""
self.hf_foken = hf_foken
self.dataset_name = dataset_name
self.organization_name = organization
self.dataset_private = private
self.verbose = verbose
def setup(self, flagging_dir):
"""
Params:
flagging_dir (str): local directory where the dataset is cloned,
updated, and pushed from.
"""
try:
import huggingface_hub
except (ImportError, ModuleNotFoundError):
raise ImportError("Package `huggingface_hub` not found is needed "
"for HuggingFaceDatasetSaver. Try 'pip install huggingface_hub'.")
path_to_dataset_repo = huggingface_hub.create_repo(
name=self.dataset_name, token=self.hf_foken,
private=self.dataset_private, repo_type="dataset", exist_ok=True)
self.flagging_dir = flagging_dir
self.dataset_dir = os.path.join(flagging_dir, self.dataset_name)
self.repo = huggingface_hub.Repository(
local_dir=self.dataset_dir, clone_from=path_to_dataset_repo,
use_auth_token=self.hf_foken)
self.repo.git_pull()
#Should filename be user-specified?
self.log_file = os.path.join(self.dataset_dir, "data.csv")
def flag(self, interface, input_data, output_data, flag_option=None,
flag_index=None, username=None, path=None):
# Note flag_index, username, path are not currently used
is_new = not os.path.exists(self.log_file)
with open(self.log_file, "a", newline="") as csvfile:
writer = csv.writer(csvfile)
# Generate the headers
if is_new:
headers = [interface["label"] for interface in interface.config["input_components"]]
headers += [interface["label"] for interface in interface.config["output_components"]]
if interface.flagging_options is not None:
headers.append("flag")
writer.writerow(headers)
# Generate the row corresponding to the flagged sample
csv_data = []
for i, input in enumerate(interface.input_components):
csv_data.append(input.save_flagged(self.dataset_dir, interface.config["input_components"][i]["label"], input_data[i], None))
for i, output in enumerate(interface.output_components):
csv_data.append(output.save_flagged(self.dataset_dir, interface.config["output_components"][i]["label"], output_data[i], None) if
output_data[i] is not None else "")
if flag_option is not None:
csv_data.append(flag_option)
# Write the rows
writer.writerow(csv_data)
# return number of samples in dataset
with open(self.log_file, "r") as csvfile:
line_count = len([None for row in csv.reader(csvfile)]) - 1
# push the repo
self.repo.push_to_hub(
commit_message="Flagged sample #{}".format(line_count))
return line_count

View File

@ -11,26 +11,30 @@ import markdown2
import numpy as np
import os
import pkg_resources
import requests
import random
import sys
import time
import warnings
import webbrowser
import weakref
from gradio import networking, strings, utils, encryptor, queue
from gradio.inputs import get_input_instance
from gradio.outputs import get_output_instance
from gradio.interpretation import quantify_difference_in_label, get_regression_or_classification_value
from gradio.external import load_interface, load_from_pipeline
from gradio.flagging import FlaggingCallback, CSVLogger
from gradio.inputs import get_input_instance
from gradio.interpretation import quantify_difference_in_label, get_regression_or_classification_value
from gradio.outputs import get_output_instance
class Interface:
"""
Interfaces are created with Gradio by constructing a `gradio.Interface()` object or by calling `gradio.Interface.load()`.
Gradio interfaces are created by constructing a `Interface` object
with a locally-defined function, or with `Interface.load()` with the path
to a repo or by `Interface.from_pipeline()` with a Transformers Pipeline.
"""
instances = weakref.WeakSet() # stores references to all currently existing Interface instances
# stores references to all currently existing Interface instances
instances = weakref.WeakSet()
@classmethod
def get_instances(cls):
@ -76,8 +80,9 @@ class Interface:
examples_per_page=10, live=False, layout="unaligned", show_input=True, show_output=True,
capture_session=None, interpretation=None, num_shap=2.0, theme=None, repeat_outputs_per_model=True,
title=None, description=None, article=None, thumbnail=None,
css=None, height=500, width=900, allow_screenshot=True, allow_flagging=None, flagging_options=None,
encrypt=False, show_tips=None, flagging_dir="flagged", analytics_enabled=None, enable_queue=None, api_mode=None):
css=None, height=None, width=None, allow_screenshot=True, allow_flagging=None, flagging_options=None,
encrypt=None, show_tips=None, flagging_dir="flagged", analytics_enabled=None, enable_queue=None, api_mode=None,
flagging_callback=CSVLogger()):
"""
Parameters:
fn (Callable): the function to wrap an interface around.
@ -100,7 +105,7 @@ class Interface:
allow_screenshot (bool): if False, users will not see a button to take a screenshot of the interface.
allow_flagging (bool): if False, users will not see a button to flag an input and output.
flagging_options (List[str]): if not None, provides options a user must select when flagging.
encrypt (bool): If True, flagged data will be encrypted by key provided by creator at launch
encrypt (bool): DEPRECATED. If True, flagged data will be encrypted by key provided by creator at launch
flagging_dir (str): what to name the dir where flagged data is stored.
show_tips (bool): DEPRECATED. if True, will occasionally show tips about new Gradio features
enable_queue (bool): DEPRECATED. if True, inference requests will be served through a queue instead of with parallel threads. Required for longer inference times (> 1min) to prevent timeout.
@ -142,7 +147,7 @@ class Interface:
self.capture_session = capture_session
if capture_session is not None:
warnings.warn("The `capture_session` parameter in the `Interface` will be deprecated in the near future.")
warnings.warn("The `capture_session` parameter in the `Interface` is deprecated and has no effect.")
self.session = None
self.title = title
@ -177,12 +182,14 @@ class Interface:
self.simple_server = None
self.allow_screenshot = allow_screenshot
# For allow_flagging and analytics_enabled: (1) first check for parameter, (2) check for environment variable, (3) default to True
self.allow_flagging = allow_flagging if allow_flagging is not None else os.getenv("GRADIO_ALLOW_FLAGGING", "True") == "True"
self.analytics_enabled = analytics_enabled if analytics_enabled is not None else os.getenv("GRADIO_ANALYTICS_ENABLED", "True") == "True"
self.analytics_enabled = analytics_enabled if analytics_enabled is not None else os.getenv("GRADIO_ANALYTICS_ENABLED", "True")=="True"
self.allow_flagging = allow_flagging if allow_flagging is not None else os.getenv("GRADIO_ALLOW_FLAGGING", "True")=="True"
self.flagging_options = flagging_options
self.flagging_callback: FlaggingCallback = flagging_callback
self.flagging_dir = flagging_dir
self.encrypt = encrypt
self.save_to = None
self.share = None
self.share_url = None
@ -197,25 +204,30 @@ class Interface:
self.enable_queue = enable_queue
if self.enable_queue is not None:
warnings.warn("The `enable_queue` parameter in the `Interface` will be deprecated. Please use the `enable_queue` parameter in `launch()` instead")
warnings.warn("The `enable_queue` parameter in the `Interface`"
"will be deprecated and may not work properly. "
"Please use the `enable_queue` parameter in "
"`launch()` instead")
self.height = height
self.width = width
if self.height is not None or self.width is not None:
warnings.warn(
"The `width` and `height` parameters in the `Interface` class"
"will be deprecated. Please provide these parameters"
"in `launch()` instead")
self.encrypt = encrypt
if self.encrypt is not None:
warnings.warn(
"The `encrypt` parameter in the `Interface` class"
"will be deprecated. Please provide this parameter"
"in `launch()` instead")
if api_mode is not None:
warnings.warn("The `api_mode` parameter in the `Interface` is deprecated.")
self.api_mode = False
if self.capture_session:
try:
import tensorflow as tf
self.session = tf.get_default_graph(), \
tf.keras.backend.get_session()
except (ImportError, AttributeError):
# If they are using TF >= 2.0 or don't have TF,
# just ignore this.
pass
if self.allow_flagging:
os.makedirs(self.flagging_dir, exist_ok=True)
data = {'fn': fn,
'inputs': inputs,
'outputs': outputs,
@ -351,18 +363,7 @@ class Interface:
for predict_fn in self.predict:
start = time.time()
if self.capture_session and self.session is not None:
graph, sess = self.session
with graph.as_default(), sess.as_default():
prediction = predict_fn(*processed_input)
else:
try:
prediction = predict_fn(*processed_input)
except ValueError as exception:
if str(exception).endswith("is not an element of this graph."):
raise ValueError(strings.en["TF1_ERROR"])
else:
raise exception
prediction = predict_fn(*processed_input)
duration = time.time() - start
if len(self.output_components) == len(self.predict):
@ -509,19 +510,7 @@ class Interface:
processed_input = [input_component.preprocess(raw_input[i])
for i, input_component in enumerate(self.input_components)]
interpreter = self.interpretation
if self.capture_session and self.session is not None:
graph, sess = self.session
with graph.as_default(), sess.as_default():
interpretation = interpreter(*processed_input)
else:
try:
interpretation = interpreter(*processed_input)
except ValueError as exception:
if str(exception).endswith("is not an element of this graph."):
raise ValueError(strings.en["TF1_ERROR"])
else:
raise exception
interpretation = interpreter(*processed_input)
if len(raw_input) == 1:
interpretation = [interpretation]
return interpretation, []
@ -557,7 +546,8 @@ class Interface:
def launch(self, inline=None, inbrowser=None, share=False, debug=False,
auth=None, auth_message=None, private_endpoint=None,
prevent_thread_lock=False, show_error=True, server_name=None,
server_port=None, show_tips=False, enable_queue=False):
server_port=None, show_tips=False, enable_queue=False,
height=500, width=900, encrypt=False):
"""
Launches the webserver that serves the UI for the interface.
Parameters:
@ -578,6 +568,9 @@ class Interface:
app (flask.Flask): Flask app object
path_to_local_server (str): Locally accessible link
share_url (str): Publicly accessible link (if share=True)
width (bool): The width of the <iframe> element containing the interface (used if inline=True)
height (bool): The height of the <iframe> element containing the interface (used if inline=True)
encrypt (bool): If True, flagged data will be encrypted by key provided by creator at launch
"""
# Set up local flask server
config = self.get_config_file()
@ -588,6 +581,10 @@ class Interface:
self.auth_message = auth_message
self.show_tips = show_tips
self.show_error = show_error
self.height = self.height or height # if height is not set in constructor, use the one provided here
self.width = self.width or width # if width is not set in constructor, use the one provided here
if self.encrypt is None:
self.encrypt = encrypt # if encrypt is not set in constructor, use the one provided here
# Request key for encryption
if self.encrypt:
@ -598,6 +595,10 @@ class Interface:
if self.enable_queue is None:
self.enable_queue = enable_queue
# Setup flagging
if self.allow_flagging:
self.flagging_callback.setup(self.flagging_dir)
# Launch local flask server
server_port, path_to_local_server, app, thread, server = networking.start_server(
self, server_name, server_port, self.auth)

View File

@ -25,8 +25,8 @@ import urllib.parse
import urllib.request
from werkzeug.security import safe_join
from werkzeug.serving import make_server
from gradio import encryptor
from gradio import queue
from gradio import encryptor, queue
from gradio.tunneling import create_tunnel
# By default, the http server will try to open on port 7860. If not available, 7861, 7862, etc.
@ -209,9 +209,10 @@ def predict():
output = {"data": prediction, "durations": durations, "avg_durations": avg_durations}
if app.interface.allow_flagging == "auto":
try:
flag_index = flag_data(raw_input, prediction,
flag_index = app.interface.flagging_handler.flag(raw_input, prediction,
flag_option=(None if app.interface.flagging_options is None else ""),
username=current_user.id if current_user.is_authenticated else None)
username=current_user.id if current_user.is_authenticated else None,
flag_path=os.path.join(app.cwd, app.interface.flagging_dir))
output["flag_index"] = flag_index
except Exception as e:
print(str(e))
@ -281,90 +282,12 @@ def log_feature_analytics(feature):
pass # do not push analytics if no network
def flag_data(input_data, output_data, flag_option=None, flag_index=None, username=None, flag_path=None):
if flag_path is None:
flag_path = os.path.join(app.cwd, app.interface.flagging_dir)
log_fp = "{}/log.csv".format(flag_path)
encryption_key = app.interface.encryption_key if app.interface.encrypt else None
is_new = not os.path.exists(log_fp)
if flag_index is None:
csv_data = []
for i, interface in enumerate(app.interface.input_components):
csv_data.append(interface.save_flagged(
flag_path, app.interface.config["input_components"][i]["label"], input_data[i], encryption_key))
for i, interface in enumerate(app.interface.output_components):
csv_data.append(interface.save_flagged(
flag_path, app.interface.config["output_components"][i]["label"], output_data[i], encryption_key) if output_data[i] is not None else "")
if flag_option is not None:
csv_data.append(flag_option)
if username is not None:
csv_data.append(username)
csv_data.append(str(datetime.datetime.now()))
if is_new:
headers = [interface["label"]
for interface in app.interface.config["input_components"]]
headers += [interface["label"]
for interface in app.interface.config["output_components"]]
if app.interface.flagging_options is not None:
headers.append("flag")
if username is not None:
headers.append("username")
headers.append("timestamp")
def replace_flag_at_index(file_content):
file_content = io.StringIO(file_content)
content = list(csv.reader(file_content))
header = content[0]
flag_col_index = header.index("flag")
content[flag_index][flag_col_index] = flag_option
output = io.StringIO()
writer = csv.writer(output)
writer.writerows(content)
return output.getvalue()
if app.interface.encrypt:
output = io.StringIO()
if not is_new:
with open(log_fp, "rb") as csvfile:
encrypted_csv = csvfile.read()
decrypted_csv = encryptor.decrypt(
app.interface.encryption_key, encrypted_csv)
file_content = decrypted_csv.decode()
if flag_index is not None:
file_content = replace_flag_at_index(file_content)
output.write(file_content)
writer = csv.writer(output)
if flag_index is None:
if is_new:
writer.writerow(headers)
writer.writerow(csv_data)
with open(log_fp, "wb") as csvfile:
csvfile.write(encryptor.encrypt(
app.interface.encryption_key, output.getvalue().encode()))
else:
if flag_index is None:
with open(log_fp, "a", newline="") as csvfile:
writer = csv.writer(csvfile)
if is_new:
writer.writerow(headers)
writer.writerow(csv_data)
else:
with open(log_fp) as csvfile:
file_content = csvfile.read()
file_content = replace_flag_at_index(file_content)
with open(log_fp, "w", newline="") as csvfile: # newline parameter needed for Windows
csvfile.write(file_content)
with open(log_fp, "r") as csvfile:
line_count = len([None for row in csv.reader(csvfile)]) - 1
return line_count
@app.route("/api/flag/", methods=["POST"])
@login_check
def flag():
log_feature_analytics('flag')
data = request.json['data']
flag_data(data['input_data'], data['output_data'], data.get("flag_option"), data.get("flag_index"),
app.interface.flagging_callback.flag(app.interface, data['input_data'], data['output_data'], data.get("flag_option"), data.get("flag_index"),
current_user.id if current_user.is_authenticated else None)
return jsonify(success=True)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 KiB

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -9,7 +9,7 @@ import transformers
WARNING: These tests have an external dependency: namely that Hugging Face's Hub and Space APIs do not change, and they keep their most famous models up. So if, e.g. Spaces is down, then these test will not pass.
"""
os.environ["GRADIO_ANALYTICS_ENABLED"] = "" # Disables analytics
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
class TestHuggingFaceModelAPI(unittest.TestCase):

31
test/test_flagging.py Normal file
View File

@ -0,0 +1,31 @@
import gradio as gr
from gradio import flagging
import tempfile
import unittest
import unittest.mock as mock
class TestFlagging(unittest.TestCase):
def test_default_flagging_handler(self):
with tempfile.TemporaryDirectory() as tmpdirname:
io = gr.Interface(lambda x: x, "text", "text", flagging_dir=tmpdirname)
io.launch(prevent_thread_lock=True)
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
self.assertEqual(row_count, 1) # 2 rows written including header
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
self.assertEqual(row_count, 2) # 3 rows written including header
io.close()
def test_simple_csv_flagging_handler(self):
with tempfile.TemporaryDirectory() as tmpdirname:
io = gr.Interface(lambda x: x, "text", "text", flagging_dir=tmpdirname, flagging_callback=flagging.SimpleCSVLogger())
io.launch(prevent_thread_lock=True)
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
self.assertEqual(row_count, 0) # no header
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
self.assertEqual(row_count, 1) # no header
io.close()
if __name__ == '__main__':
unittest.main()

View File

@ -10,7 +10,7 @@ import tempfile
import json
os.environ["GRADIO_ANALYTICS_ENABLED"] = "" # Disables analytics
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
class InputComponent(unittest.TestCase):

View File

@ -1,15 +1,14 @@
from gradio import networking
import gradio as gr
from gradio import networking, Interface, reset_all, flagging
import unittest
import unittest.mock as mock
import ipaddress
import requests
import warnings
import tempfile
from unittest.mock import ANY
from unittest.mock import ANY, MagicMock
import urllib.request
import os
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
@ -59,7 +58,7 @@ class TestPort(unittest.TestCase):
class TestFlaskRoutes(unittest.TestCase):
def setUp(self) -> None:
self.io = gr.Interface(lambda x: x, "text", "text")
self.io = Interface(lambda x: x, "text", "text")
self.app, _, _ = self.io.launch(prevent_thread_lock=True)
self.client = self.app.test_client()
@ -106,12 +105,12 @@ class TestFlaskRoutes(unittest.TestCase):
def tearDown(self) -> None:
self.io.close()
gr.reset_all()
reset_all()
class TestAuthenticatedFlaskRoutes(unittest.TestCase):
def setUp(self) -> None:
self.io = gr.Interface(lambda x: x, "text", "text")
self.io = Interface(lambda x: x, "text", "text")
self.app, _, _ = self.io.launch(auth=("test", "correct_password"), prevent_thread_lock=True)
self.client = self.app.test_client()
@ -127,11 +126,12 @@ class TestAuthenticatedFlaskRoutes(unittest.TestCase):
def tearDown(self) -> None:
self.io.close()
gr.reset_all()
reset_all()
class TestInterfaceCustomParameters(unittest.TestCase):
def test_show_error(self):
io = gr.Interface(lambda x: 1/x, "number", "number")
io = Interface(lambda x: 1/x, "number", "number")
app, _, _ = io.launch(show_error=True, prevent_thread_lock=True)
client = app.test_client()
response = client.post('/api/predict/', json={"data": [0]})
@ -141,47 +141,39 @@ class TestInterfaceCustomParameters(unittest.TestCase):
def test_feature_logging(self):
with mock.patch('requests.post') as mock_post:
io = gr.Interface(lambda x: 1/x, "number", "number", analytics_enabled=True)
io = Interface(lambda x: 1/x, "number", "number", analytics_enabled=True)
io.launch(show_error=True, prevent_thread_lock=True)
networking.log_feature_analytics("test_feature")
mock_post.assert_called_with(networking.GRADIO_FEATURE_ANALYTICS_URL, data=ANY, timeout=ANY)
io.close()
io = gr.Interface(lambda x: 1/x, "number", "number")
print(io.analytics_enabled)
io = Interface(lambda x: 1/x, "number", "number")
io.launch(show_error=True, prevent_thread_lock=True)
with mock.patch('requests.post') as mock_post:
networking.log_feature_analytics("test_feature")
mock_post.assert_not_called()
io.close()
class TestFlagging(unittest.TestCase):
def test_num_rows_written(self):
io = gr.Interface(lambda x: x, "text", "text")
io.launch(prevent_thread_lock=True)
with tempfile.TemporaryDirectory() as tmpdirname:
row_count = networking.flag_data(["test"], ["test"], flag_path=tmpdirname)
self.assertEquals(row_count, 1) # 2 rows written including header
row_count = networking.flag_data("test", "test", flag_path=tmpdirname)
self.assertEquals(row_count, 2) # 3 rows written including header
io.close()
class TestFlagging(unittest.TestCase):
@mock.patch("requests.post")
@mock.patch("gradio.networking.flag_data")
def test_flagging_analytics(self, mock_flag, mock_post):
io = gr.Interface(lambda x: x, "text", "text", analytics_enabled=True)
def test_flagging_analytics(self, mock_post):
callback = flagging.CSVLogger()
callback.flag = mock.MagicMock()
io = Interface(lambda x: x, "text", "text", analytics_enabled=True, flagging_callback=callback)
app, _, _ = io.launch(show_error=True, prevent_thread_lock=True)
client = app.test_client()
response = client.post('/api/flag/', json={"data": {"input_data": ["test"], "output_data": ["test"]}})
mock_post.assert_any_call(networking.GRADIO_FEATURE_ANALYTICS_URL, data=ANY, timeout=ANY)
mock_flag.assert_called_once()
callback.flag.assert_called_once()
self.assertEqual(response.status_code, 200)
io.close()
@mock.patch("requests.post")
class TestInterpretation(unittest.TestCase):
def test_interpretation(self, mock_post):
io = gr.Interface(lambda x: len(x), "text", "label", interpretation="default", analytics_enabled=True)
io = Interface(lambda x: len(x), "text", "label", interpretation="default", analytics_enabled=True)
app, _, _ = io.launch(prevent_thread_lock=True)
client = app.test_client()
io.interpret = mock.MagicMock(return_value=(None, None))
@ -192,30 +184,30 @@ class TestInterpretation(unittest.TestCase):
class TestState(unittest.TestCase):
def test_state_initialization(self):
io = gr.Interface(lambda x: len(x), "text", "label")
io = Interface(lambda x: len(x), "text", "label")
app, _, _ = io.launch(prevent_thread_lock=True)
with app.test_request_context():
self.assertIsNone(networking.get_state())
def test_state_value(self):
io = gr.Interface(lambda x: len(x), "text", "label")
io = Interface(lambda x: len(x), "text", "label")
app, _, _ = io.launch(prevent_thread_lock=True)
with app.test_request_context():
networking.set_state("test")
client = app.test_client()
client.post('/api/predict/', json={"data": [0]})
self.assertEquals(networking.get_state(), "test")
self.assertEqual(networking.get_state(), "test")
class TestURLs(unittest.TestCase):
def test_url_ok(self):
urllib.request.urlopen = mock.MagicMock(return_value="test")
res = networking.url_request("http://www.gradio.app")
self.assertEquals(res, "test")
self.assertEqual(res, "test")
def test_setup_tunnel(self):
networking.create_tunnel = mock.MagicMock(return_value="test")
res = networking.setup_tunnel(None, None)
self.assertEquals(res, "test")
self.assertEqual(res, "test")
def test_url_ok(self):
res = networking.url_ok("https://www.gradio.app")
@ -224,7 +216,7 @@ class TestURLs(unittest.TestCase):
class TestQueuing(unittest.TestCase):
def test_queueing(self):
io = gr.Interface(lambda x: x, "text", "text")
io = Interface(lambda x: x, "text", "text")
app, _, _ = io.launch(prevent_thread_lock=True)
client = app.test_client()
# mock queue methods and post method