diff --git a/.gitignore b/.gitignore index 9c2407f..377bb48 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ codekit-config.json # Mac Files **/.DS_Store +**/.vscode \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 49461b7..fa26499 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,35 @@ -FROM python:2.7-alpine +FROM alpine:3.14.3 RUN apk update && apk upgrade && \ apk add \ - gcc python python-dev py-pip \ - # greenlet - musl-dev \ - # sys/queue.h - bsd-compat-headers \ - # event.h - libevent-dev \ + build-base \ + py3-pip \ + libffi-dev \ + # Package for running environment + py3-gevent \ + py3-greenlet \ + py3-gunicorn \ + python3-dbg \ + py3-zope-component \ + # file + file \ && rm -rf /var/cache/apk/* - +RUN addgroup --gid 1000 -S requestbin && adduser -S requestbin -u 1000 -G requestbin -h /opt/requestbin +USER 1000:1000 # want all dependencies first so that if it's just a code change, don't have to # rebuild as much of the container ADD requirements.txt /opt/requestbin/ RUN pip install -r /opt/requestbin/requirements.txt \ - && rm -rf ~/.pip/cache - + && rm -rf ~/.pip/cache +USER root +RUN apk del \ + build-base \ + py3-pip \ + libffi-dev +USER 1000:1000 # the code -ADD requestbin /opt/requestbin/requestbin/ +ADD requestbin /opt/requestbin/requestbin/ EXPOSE 8000 - WORKDIR /opt/requestbin -CMD gunicorn -b 0.0.0.0:8000 --worker-class gevent --workers 2 --max-requests 1000 requestbin:app - - +CMD gunicorn -b 0.0.0.0:8000 --worker-class gevent --workers 1 --max-requests 1000 requestbin.app:app diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..52e7d44 --- /dev/null +++ b/Pipfile @@ -0,0 +1,25 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] +gevent = "*" +flake8 = "*" +autopep8 = "*" +gunicorn = "*" + +[packages] +nose = "*" +feedparser = "*" +redis = "*" +msgpack-python = "*" +python-dateutil = "*" +gunicorn = "==19.9.0" +bugsnag = "*" +blinker = "*" +ProxyTypes = "*" +Flask-Cors = "*" + +[requires] +python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..a3fe60b --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,363 @@ +{ + "_meta": { + "hash": { + "sha256": "11b1390cf97ccb619fb8c87fa3c90300fa935bf2951b66a359c51123c7508e77" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "blinker": { + "hashes": [ + "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" + ], + "index": "pypi", + "version": "==1.4" + }, + "bugsnag": { + "hashes": [ + "sha256:01c2186f6c2a6f801b66d8fc73b8986bd2d4931a6ab40b720e5fd0b66757facc", + "sha256:d708b091c230fdf007eb0f49d1c71c81da27965d3d56adf690b90c259e179aa9" + ], + "index": "pypi", + "version": "==4.0.1" + }, + "click": { + "hashes": [ + "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", + "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==7.1.2" + }, + "feedparser": { + "hashes": [ + "sha256:6ca88edcaa43f428345968df903a87f020843eda5e28d7ea24a612158d61e74c", + "sha256:c9b436334258e718e224c5ef8a78088557e0d0382506360f702de10667ffde32" + ], + "index": "pypi", + "version": "==6.0.1" + }, + "flask": { + "hashes": [ + "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060", + "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.1.2" + }, + "flask-cors": { + "hashes": [ + "sha256:6bcfc100288c5d1bcb1dbb854babd59beee622ffd321e444b05f24d6d58466b8", + "sha256:cee4480aaee421ed029eaa788f4049e3e26d15b5affb6a880dade6bafad38324" + ], + "index": "pypi", + "version": "==3.0.9" + }, + "gunicorn": { + "hashes": [ + "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", + "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" + ], + "index": "pypi", + "version": "==19.9.0" + }, + "itsdangerous": { + "hashes": [ + "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", + "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.1.0" + }, + "jinja2": { + "hashes": [ + "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", + "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.11.2" + }, + "markupsafe": { + "hashes": [ + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.1.1" + }, + "msgpack-python": { + "hashes": [ + "sha256:378cc8a6d3545b532dfd149da715abae4fda2a3adb6d74e525d0d5e51f46909b" + ], + "index": "pypi", + "version": "==0.5.6" + }, + "nose": { + "hashes": [ + "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", + "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", + "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98" + ], + "index": "pypi", + "version": "==1.3.7" + }, + "proxytypes": { + "hashes": [ + "sha256:82cc41d5e7c913982b505241c7c87448ed26b6884a40c2889f2ee19d06339985", + "sha256:83e5bb089cccb23087c6e3c5d71dda9fca351b624ca5de709fddcf58dab84c84", + "sha256:f3bf78debafe15d8ccb31a0c909f820408bb678532a8be8bf737ddd50c03f298" + ], + "index": "pypi", + "version": "==0.10.0" + }, + "python-dateutil": { + "hashes": [ + "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", + "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" + ], + "index": "pypi", + "version": "==2.8.1" + }, + "redis": { + "hashes": [ + "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2", + "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24" + ], + "index": "pypi", + "version": "==3.5.3" + }, + "sgmllib3k": { + "hashes": [ + "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9" + ], + "version": "==1.0.0" + }, + "six": { + "hashes": [ + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.15.0" + }, + "webob": { + "hashes": [ + "sha256:a3c89a8e9ba0aeb17382836cdb73c516d0ecf6630ec40ec28288f3ed459ce87b", + "sha256:aa3a917ed752ba3e0b242234b2a373f9c4e2a75d35291dcbe977649bd21fd108" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.8.6" + }, + "werkzeug": { + "hashes": [ + "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", + "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.0.1" + } + }, + "develop": { + "autopep8": { + "hashes": [ + "sha256:d21d3901cb0da6ebd1e83fc9b0dfbde8b46afc2ede4fe32fbda0c7c6118ca094" + ], + "index": "pypi", + "version": "==1.5.4" + }, + "flake8": { + "hashes": [ + "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839", + "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b" + ], + "index": "pypi", + "version": "==3.8.4" + }, + "gevent": { + "hashes": [ + "sha256:10110d4881aec04f218c316cb796b18c8b2cac67ae0eb5b0c5780056757268a2", + "sha256:1628a403fc9c3ea9b35924638a4d4fbe236f60ecdf4e22ed133fbbaf0bc7cb6b", + "sha256:1cfa3674866294623e324fa5b76eba7b96744d1956a605cfe24d26c5cd890f91", + "sha256:2269574444113cb4ca1c1808ab9460a87fe25e1c34a6e36d975d4af46e4afff9", + "sha256:283a021a2e14adfad718346f18982b80569d9c3a59e97cfae1b7d4c5b017941a", + "sha256:2aa70726ad1883fe7c17774e5ccc91ac6e30334efa29bafb9b8fe8ca6091b219", + "sha256:315a63a35068183dfb9bc0331c7bb3c265ee7db8a11797cbe98dadbdb45b5d35", + "sha256:324808a8558c733f7a9734525483795d52ca3bbd5662b24b361d81c075414b1f", + "sha256:33a63f230755c6813fca39d9cea2a8894df32df2ee58fd69d8bf8fcc1d8e018e", + "sha256:5f6d48051d336561ec08995431ee4d265ac723a64bba99cc58c3eb1a4d4f5c8d", + "sha256:8d338cd6d040fe2607e5305dd7991b5960b3780ae01f804c2ac5760d31d3b2c6", + "sha256:906175e3fb25f377a0b581e79d3ed5a7d925c136ff92fd022bb3013e25f5f3a9", + "sha256:93980e51dd2e5f81899d644a0b6ef4a73008c679fcedd50e3b21cc3451ba2424", + "sha256:9bb477f514cf39dc20651b479bf1ad4f38b9a679be2bfa3e162ec0c3785dfa2a", + "sha256:a8733a01974433d91308f8c44fa6cc13428b15bb39d46540657e260ff8852cb1", + "sha256:adbb267067f56696b2babced3d0856aa39dcf14b8ccd2dffa1fab587b00c6f80", + "sha256:afc177c37de41ce9c27d351ac84cbaf34407effcab5d6641645838f39d365be1", + "sha256:b07fcbca3e819296979d82fac3d8b44f0d5ced57b9a04dffcfd194da99c8eb2d", + "sha256:b2948566003a1030e47507755fe1f446995e8671c0c67571091539e01faf94cc", + "sha256:db208e74a32cff7f55f5aa1ba5d7d1c1a086a6325c8702ae78a5c741155552ff", + "sha256:dd4c6b2f540b25c3d0f277a725bc1a900ce30a681b90a081216e31f814be453b", + "sha256:e11de4b4d107ca2f35000eb08e9c4c4621c153103b400f48a9ea95b96d8c7e0b", + "sha256:eba19bae532d0c48d489fa16815b242ce074b1f4b63e8a8e663232cbe311ead9", + "sha256:fb33dc1ab27557bccd64ad4bf81e68c8b0d780fe937b1e2c0814558798137229" + ], + "index": "pypi", + "version": "==20.9.0" + }, + "greenlet": { + "hashes": [ + "sha256:1023d7b43ca11264ab7052cb09f5635d4afdb43df55e0854498fc63070a0b206", + "sha256:124a3ae41215f71dc91d1a3d45cbf2f84e46b543e5d60b99ecc20e24b4c8f272", + "sha256:13037e2d7ab2145300676852fa069235512fdeba4ed1e3bb4b0677a04223c525", + "sha256:3af587e9813f9bd8be9212722321a5e7be23b2bc37e6323a90e592ab0c2ef117", + "sha256:41d8835c69a78de718e466dd0e6bfd4b46125f21a67c3ff6d76d8d8059868d6b", + "sha256:4481002118b2f1588fa3d821936ffdc03db80ef21186b62b90c18db4ba5e743b", + "sha256:47825c3a109f0331b1e54c1173d4e57fa000aa6c96756b62852bfa1af91cd652", + "sha256:5494e3baeacc371d988345fbf8aa4bd15555b3077c40afcf1994776bb6d77eaf", + "sha256:75e4c27188f28149b74e7685809f9227410fd15432a4438fc48627f518577fa5", + "sha256:97f2b01ab622a4aa4b3724a3e1fba66f47f054c434fbaa551833fa2b41e3db51", + "sha256:a34023b9eabb3525ee059f3bf33a417d2e437f7f17e341d334987d4091ae6072", + "sha256:ac85db59aa43d78547f95fc7b6fd2913e02b9e9b09e2490dfb7bbdf47b2a4914", + "sha256:be7a79988b8fdc5bbbeaed69e79cfb373da9759242f1565668be4fb7f3f37552", + "sha256:bee111161420f341a346731279dd976be161b465c1286f82cc0779baf7b729e8", + "sha256:ccd62f09f90b2730150d82f2f2ffc34d73c6ce7eac234aed04d15dc8a3023994", + "sha256:d3436110ca66fe3981031cc6aff8cc7a40d8411d173dde73ddaa5b8445385e2d", + "sha256:e495096e3e2e8f7192afb6aaeba19babc4fb2bdf543d7b7fed59e00c1df7f170", + "sha256:e66a824f44892bc4ec66c58601a413419cafa9cec895e63d8da889c8a1a4fa4a" + ], + "markers": "platform_python_implementation == 'CPython'", + "version": "==0.4.17" + }, + "gunicorn": { + "hashes": [ + "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", + "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" + ], + "index": "pypi", + "version": "==19.9.0" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", + "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.6.0" + }, + "pyflakes": { + "hashes": [ + "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92", + "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.2.0" + }, + "toml": { + "hashes": [ + "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", + "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" + ], + "version": "==0.10.1" + }, + "zope.event": { + "hashes": [ + "sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42", + "sha256:5e76517f5b9b119acf37ca8819781db6c16ea433f7e2062c4afc2b6fbedb1330" + ], + "version": "==4.5.0" + }, + "zope.interface": { + "hashes": [ + "sha256:040f833694496065147e76581c0bf32b229a8b8c5eda120a0293afb008222387", + "sha256:11198b44e4a3d8c7a80cc20bbdd65522258a4d82fe467cd310c9fcce8ffe2ed2", + "sha256:121a9dccfe0c34be9c33b2c28225f0284f9b8e090580ffdff26c38fa16c7ffe1", + "sha256:15f3082575e7e19581a80b866664f843719b647a7f7189c811ba7f9ab3309f83", + "sha256:1d73d8986f948525536956ddd902e8a587a6846ebf4492117db16daba2865ddf", + "sha256:208e82f73b242275b8566ac07a25158e7b21fa2f14e642a7881048430612d1a6", + "sha256:2557833df892558123d791d6ff80ac4a2a0351f69c7421c7d5f0c07db72c8865", + "sha256:25ea6906f9987d42546329d06f9750e69f0ee62307a2e7092955ed0758e64f09", + "sha256:2c867914f7608674a555ac8daf20265644ac7be709e1da7d818089eebdfe544e", + "sha256:2eadac20711a795d3bb7a2bfc87c04091cb5274d9c3281b43088a1227099b662", + "sha256:37999d5ebd5d7bcd32438b725ca3470df05a7de8b1e9c0395bef24296b31ca99", + "sha256:3ae8946d51789779f76e4fa326fd6676d8c19c1c3b4c4c5e9342807185264875", + "sha256:5636cd7e60583b1608044ae4405e91575399430e66a5e1812f4bf30bcc55864e", + "sha256:570e637cb6509998555f7e4af13006d89fad6c09cfc5c4795855385391063e4b", + "sha256:590a40447ff3803c44050ce3c17c3958f11ca028dae3eacdd7b96775184394fa", + "sha256:5aab51b9c1af1b8a84f40aa49ffe1684d41810b18d6c3e94aa50194e0a563f01", + "sha256:5ffe4e0753393bcbcfc9a58133ed3d3a584634cc7cc2e667f8e3e6fbcbb2155d", + "sha256:663982381bd428a275a841009e52983cc69c471a4979ce01344fadbf72cf353d", + "sha256:6d06bf8e24dd6c473c4fbd8e16a83bd2e6d74add6ba25169043deb46d497b211", + "sha256:6e5b9a4bf133cf1887b4a04c21c10ca9f548114f19c83957b2820d5c84254940", + "sha256:70a2aed9615645bbe9d82c0f52bc7e676d2c0f8a63933d68418e0cb307f30536", + "sha256:7750746421c4395e3d2cc3d805919f4f57bb9f2a9a0ccd955566a9341050a1b4", + "sha256:7fc8708bc996e50fc7a9a2ad394e1f015348e389da26789fa6916630237143d7", + "sha256:91abd2f080065a7c007540f6bbd93ef7bdbbffa6df4a4cfab3892d8623b83c98", + "sha256:988f8b2281f3d95c66c01bdb141cefef1cc97db0d473c25c3fe2927ef00293b9", + "sha256:9f56121d8a676802044584e6cc41250bbcde069d8adf725b9b817a6b0fd87f09", + "sha256:a0f51536ce6e817a7aa25b0dca8b62feb210d4dc22cabfe8d1a92d47979372cd", + "sha256:a1cdd7390d7f66ddcebf545203ca3728c4890d605f9f2697bc8e31437906e8e7", + "sha256:b10eb4d0a77609679bf5f23708e20b1cd461a1643bd8ea42b1ca4149b1a5406c", + "sha256:b274ac8e511b55ffb62e8292316bd2baa80c10e9fe811b1aa5ce81da6b6697d8", + "sha256:c75b502af2c83fcfa2ee9c2257c1ba5806634a91a50db6129ff70e67c42c7e7b", + "sha256:c9c8e53a5472b77f6a391b515c771105011f4b40740ce53af8428d1c8ca20004", + "sha256:d867998a56c5133b9d31992beb699892e33b72150a8bf40f86cb52b8c606c83f", + "sha256:eb566cab630ec176b2d6115ed08b2cf4d921b47caa7f02cca1b4a9525223ee94", + "sha256:f61e6b95b414431ffe9dc460928fe9f351095fde074e2c2f5c6dda7b67a2192d", + "sha256:f718675fd071bcce4f7cbf9250cbaaf64e2e91ef1b0b32a1af596e7412647556", + "sha256:f9d4bfbd015e4b80dbad11c97049975f94592a6a0440e903ee647309f6252a1f", + "sha256:fae50fc12a5e8541f6f1cc4ed744ca8f76a9543876cf63f618fb0e6aca8f8375", + "sha256:fcf9c8edda7f7b2fd78069e97f4197815df5e871ec47b0f22580d330c6dec561", + "sha256:fdedce3bc5360bd29d4bb90396e8d4d3c09af49bc0383909fe84c7233c5ee675" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==5.1.2" + } + } +} diff --git a/app.json b/app.json index f114580..dce7288 100644 --- a/app.json +++ b/app.json @@ -1,9 +1,7 @@ { "name": "requestbin", "description": "Inspect HTTP requests. Debug webhooks.", - "website": "http://requestb.in/", - "repository": "https://github.com/Runscope/requestbin", - "logo": "http://requestb.in/static/img/logo-2x.png", + "repository": "https://github.com/cellebyte/requestbin", "keywords": ["python"], "env": { "REALM": { diff --git a/requestbin/__init__.py b/requestbin/__init__.py index b7e978a..502a9d6 100644 --- a/requestbin/__init__.py +++ b/requestbin/__init__.py @@ -1,10 +1,58 @@ -import config import os -from cStringIO import StringIO - +from io import BytesIO from flask import Flask from flask_cors import CORS +import requestbin.config as config +from requestbin.filters import (approximate_time, exact_time, friendly_size, + friendly_time, short_date, status_class, to_qs) +from werkzeug.middleware.proxy_fix import ProxyFix + + +class MyApplication(Flask): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.wsgi_app = WSGIRawBody(ProxyFix(self.wsgi_app)) + self.add_config() + self.add_filters() + + def add_config(self): + self.debug = config.DEBUG + self.secret_key = config.FLASK_SESSION_SECRET_KEY + self.root_path = os.path.abspath(os.path.dirname(__file__)) + if config.BUGSNAG_KEY: + import bugsnag + from bugsnag.flask import handle_exceptions + bugsnag.configure( + api_key=config.BUGSNAG_KEY, + project_root=self.root_path, + # 'production' is a magic string for bugsnag, rest are arbitrary + release_stage=config.REALM.replace("prod", "production"), + notify_release_stages=["production", "test"], + use_ssl=True + ) + handle_exceptions(self) + if os.environ.get('ENABLE_CORS', config.ENABLE_CORS): + _ = CORS( + self, + resources={ + r"*": { + "origins": os.environ.get( + 'CORS_ORIGINS', config.CORS_ORIGINS + ) + } + } + ) + + def add_filters(self): + self.jinja_env.filters['status_class'] = status_class + self.jinja_env.filters['friendly_time'] = friendly_time + self.jinja_env.filters['friendly_size'] = friendly_size + self.jinja_env.filters['to_qs'] = to_qs + self.jinja_env.filters['approximate_time'] = approximate_time + self.jinja_env.filters['exact_time'] = exact_time + self.jinja_env.filters['short_date'] = short_date + class WSGIRawBody(object): def __init__(self, application): @@ -17,7 +65,7 @@ def __call__(self, environ, start_response): body = environ['wsgi.input'].read(length) environ['raw'] = body - environ['wsgi.input'] = StringIO(body) + environ['wsgi.input'] = BytesIO(body) # Call the wrapped application app_iter = self.application(environ, self._sr_callback(start_response)) @@ -31,54 +79,3 @@ def callback(status, headers, exc_info=None): # Call upstream start_response start_response(status, headers, exc_info) return callback - - - -app = Flask(__name__) - -if os.environ.get('ENABLE_CORS', config.ENABLE_CORS): - cors = CORS(app, resources={r"*": {"origins": os.environ.get('CORS_ORIGINS', config.CORS_ORIGINS)}}) - -from werkzeug.contrib.fixers import ProxyFix -app.wsgi_app = WSGIRawBody(ProxyFix(app.wsgi_app)) - -app.debug = config.DEBUG -app.secret_key = config.FLASK_SESSION_SECRET_KEY -app.root_path = os.path.abspath(os.path.dirname(__file__)) - -if config.BUGSNAG_KEY: - import bugsnag - from bugsnag.flask import handle_exceptions - bugsnag.configure( - api_key=config.BUGSNAG_KEY, - project_root=app.root_path, - # 'production' is a magic string for bugsnag, rest are arbitrary - release_stage = config.REALM.replace("prod", "production"), - notify_release_stages=["production", "test"], - use_ssl = True - ) - handle_exceptions(app) - -from filters import * -app.jinja_env.filters['status_class'] = status_class -app.jinja_env.filters['friendly_time'] = friendly_time -app.jinja_env.filters['friendly_size'] = friendly_size -app.jinja_env.filters['to_qs'] = to_qs -app.jinja_env.filters['approximate_time'] = approximate_time -app.jinja_env.filters['exact_time'] = exact_time -app.jinja_env.filters['short_date'] = short_date - -app.add_url_rule('/', 'views.home') -app.add_url_rule('/', 'views.bin', methods=['GET', 'POST', 'DELETE', 'PUT', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE']) - -app.add_url_rule('/docs/', 'views.docs') -app.add_url_rule('/api/v1/bins', 'api.bins', methods=['POST']) -app.add_url_rule('/api/v1/bins/', 'api.bin', methods=['GET']) -app.add_url_rule('/api/v1/bins//requests', 'api.requests', methods=['GET']) -app.add_url_rule('/api/v1/bins//requests/', 'api.request', methods=['GET']) - -app.add_url_rule('/api/v1/stats', 'api.stats') - -# app.add_url_rule('/robots.txt', redirect_to=url_for('static', filename='robots.txt')) - -from requestbin import api, views diff --git a/requestbin/api.py b/requestbin/api.py index 2a83065..b818b78 100644 --- a/requestbin/api.py +++ b/requestbin/api.py @@ -1,8 +1,9 @@ import json -import operator -from flask import session, make_response, request, render_template -from requestbin import app, db +from flask import make_response, request, session + +from requestbin import db + def _response(object, code=200): jsonp = request.args.get('jsonp') @@ -16,7 +17,6 @@ def _response(object, code=200): return resp -@app.endpoint('api.bins') def bins(): private = request.form.get('private') in ['true', 'on'] bin = db.create_bin(private) @@ -25,7 +25,6 @@ def bins(): return _response(bin.to_dict()) -@app.endpoint('api.bin') def bin(name): try: bin = db.lookup_bin(name) @@ -35,7 +34,6 @@ def bin(name): return _response(bin.to_dict()) -@app.endpoint('api.requests') def requests(bin): try: bin = db.lookup_bin(bin) @@ -45,7 +43,6 @@ def requests(bin): return _response([r.to_dict() for r in bin.requests]) -@app.endpoint('api.request') def request_(bin, name): try: bin = db.lookup_bin(bin) @@ -59,7 +56,6 @@ def request_(bin, name): return _response({'error': "Request not found"}, 404) -@app.endpoint('api.stats') def stats(): stats = { 'bin_count': db.count_bins(), diff --git a/requestbin/app.py b/requestbin/app.py new file mode 100644 index 0000000..daf08c4 --- /dev/null +++ b/requestbin/app.py @@ -0,0 +1,42 @@ +from requestbin import MyApplication +import requestbin.views as views +import requestbin.api as api + + +app = MyApplication(__name__) + +app.add_url_rule('/', 'views.home', views.home) +views.bin.methods = [ + 'GET', + 'POST', + 'DELETE', + 'PUT', + 'OPTIONS', + 'HEAD', + 'PATCH', + 'TRACE' +] +app.add_url_rule('/', 'views.bin', views.bin) + +api.bins.provide_automatic_options = False +api.bins.methods = ['POST'] +app.add_url_rule( + '/api/v1/bins', 'api.bins', api.bins) + +api.bin.provide_automatic_options = False +api.bin.methods = ['GET'] +app.add_url_rule( + '/api/v1/bins/', 'api.bin', api.bin) + +api.requests.provide_automatic_options = False +api.requests.methods = ['GET'] +app.add_url_rule('/api/v1/bins//requests', + 'api.requests', api.requests, methods=['GET']) + + +api.request_.provide_automatic_options = False +api.request_.methods = ['GET'] +app.add_url_rule('/api/v1/bins//requests/', 'api.request_', api.request_) + + +app.add_url_rule('/api/v1/stats', 'api.stats', api.stats) diff --git a/requestbin/config.py b/requestbin/config.py index 6da3f0e..eb6bd71 100644 --- a/requestbin/config.py +++ b/requestbin/config.py @@ -1,4 +1,5 @@ -import os, urlparse +import os +import urllib.parse as urlparse DEBUG = os.environ.get("DEBUG", True) REALM = os.environ.get('REALM', 'local') @@ -14,7 +15,7 @@ STORAGE_BACKEND = "requestbin.storage.memory.MemoryStorage" MAX_RAW_SIZE = int(os.environ.get('MAX_RAW_SIZE', 1024*10)) IGNORE_HEADERS = [] -MAX_REQUESTS = os.environ.get("MAX_REQUESTS", 20) +MAX_REQUESTS = int(os.environ.get("MAX_REQUESTS", 20)) CLEANUP_INTERVAL = 3600 MAX_JSON_TO_PRETTYPARSE_IN_BYTES = int(os.environ.get('MAX_JSON_TO_PRETTYPARSE_IN_BYTES', 300*1024)) diff --git a/requestbin/db.py b/requestbin/db.py index e1ca0be..378fc58 100644 --- a/requestbin/db.py +++ b/requestbin/db.py @@ -1,5 +1,3 @@ -import feedparser -import time import re from requestbin import config @@ -9,27 +7,35 @@ storage_module, storage_class = storage_backend.rsplit('.', 1) try: - klass = getattr(__import__(storage_module, fromlist=[storage_class]), storage_class) -except ImportError, e: - raise ImportError("Unable to load storage backend '{}': {}".format(storage_backend, e)) + klass = getattr(__import__(storage_module, fromlist=[ + storage_class]), storage_class) +except ImportError as e: + raise ImportError( + "Unable to load storage backend '{}': {}".format(storage_backend, e)) db = klass(bin_ttl) + def create_bin(private=False): return db.create_bin(private) + def create_request(bin, request): return db.create_request(bin, request) + def lookup_bin(name): - name=re.split(r"[/.]", name)[0] + name = re.split(r"[/.]", name)[0] return db.lookup_bin(name) + def count_bins(): return db.count_bins() + def count_requests(): return db.count_requests() + def avg_req_size(): return db.avg_req_size() diff --git a/requestbin/filters.py b/requestbin/filters.py index a9b51c5..944ffb6 100644 --- a/requestbin/filters.py +++ b/requestbin/filters.py @@ -1,12 +1,10 @@ import datetime from dateutil.parser import parse -import hashlib -import os import time -import urllib + def approximate_time(ts): - if not isinstance(ts, (int, long, float, complex)): + if not isinstance(ts, (int, float, complex)): return "" now = time.time() @@ -44,11 +42,11 @@ def friendly_size(bytes): def status_class(status_code): status_code = str(status_code or "0") lookup = { - "0" : "", - "2" : "ok", - "3" : "info", - "4" : "warning", - "5" : "error" + "0": "", + "2": "ok", + "3": "info", + "4": "warning", + "5": "error" } return lookup.get(status_code[0], "") @@ -71,20 +69,20 @@ def friendly_time(secs): def friendly_number(input): - if not isinstance(input, (int, long, float, complex)): + if not isinstance(input, (int, float, complex)): return "" return "{:,}".format(input) def exact_time(ts): - if not isinstance(ts, (int, long, float, complex)): + if not isinstance(ts, (int, float, complex)): return None return datetime.datetime.utcfromtimestamp(ts) def time_class(secs): - if not isinstance(secs, (int, long, float, complex)): + if not isinstance(secs, (int, float, complex)): return "" ms = secs * 1000.0 @@ -92,7 +90,7 @@ def time_class(secs): return "error" if ms > 1000: - return "warning" + return "warning" return "" @@ -112,14 +110,14 @@ def to_qs(params_dict): qs = qs + u"{}={}".format(k, v) return qs - + def short_date(input): dt = None - if isinstance(input, (str, unicode)): + if isinstance(input, (str)): dt = parse(input) - elif isinstance(input, (int, long, float, complex)): + elif isinstance(input, (int, float, complex)): dt = datetime.datetime.utcfromtimestamp(float(input)) else: return "" - return dt.strftime("%b %d, %Y") \ No newline at end of file + return dt.strftime("%b %d, %Y") diff --git a/requestbin/models.py b/requestbin/models.py index 69322ae..148cc2a 100644 --- a/requestbin/models.py +++ b/requestbin/models.py @@ -3,7 +3,6 @@ import time import datetime import os -import re import logging import msgpack @@ -14,6 +13,7 @@ from requestbin import config + class Bin(object): max_requests = config.MAX_REQUESTS @@ -28,11 +28,11 @@ def __init__(self, private=False): def json(self): return json.dumps(self.to_dict()) - + def to_dict(self): return dict( - private=self.private, - color=self.color, + private=self.private, + color=self.color, name=self.name, request_count=self.request_count) @@ -55,20 +55,21 @@ def request_count(self): def add(self, request): self.requests.insert(0, Request(request)) - if len(self.requests) > self.max_requests: - for _ in xrange(self.max_requests, len(self.requests)): + if self.request_count > self.max_requests: + for _ in range(self.max_requests, len(self.requests)): self.requests.pop(self.max_requests) class Request(object): ignore_headers = config.IGNORE_HEADERS - max_raw_size = config.MAX_RAW_SIZE + max_raw_size = config.MAX_RAW_SIZE def __init__(self, input=None): if input: self.id = tinyid(6) self.time = time.time() - self.remote_addr = input.headers.get('X-Forwarded-For', input.remote_addr) + self.remote_addr = input.headers.get( + 'X-Forwarded-For', input.remote_addr) self.method = input.method self.headers = dict(input.headers) @@ -89,12 +90,11 @@ def __init__(self, input=None): self.content_length = len(self.raw) # for header in self.ignore_headers: - # self.raw = re.sub(r'{}: [^\n]+\n'.format(header), + # self.raw = re.sub(r'{}: [^\n]+\n'.format(header), # '', self.raw, flags=re.IGNORECASE) if self.raw and len(self.raw) > self.max_raw_size: self.raw = self.raw[0:self.max_raw_size] - def to_dict(self): return dict( id=self.id, @@ -168,4 +168,3 @@ def load(data): # else: # fields.append((k,v)) # return iter(sorted(fields) + sorted(files)) - diff --git a/requestbin/static/css/styles.css b/requestbin/static/css/styles.css index c98e0b8..3c1f82e 100644 --- a/requestbin/static/css/styles.css +++ b/requestbin/static/css/styles.css @@ -46,7 +46,7 @@ hr { padding: 4px 12px; color: #ffffff; } -.runscope-wrap { +.formal-wrap { padding: 4px 20px; background: #f9f9f9; border-bottom: 1px solid #eeeeee; diff --git a/requestbin/static/img/ico-github.png b/requestbin/static/img/ico-github.png new file mode 100644 index 0000000..12b4fb0 Binary files /dev/null and b/requestbin/static/img/ico-github.png differ diff --git a/requestbin/static/img/logo-runscope-1x.png b/requestbin/static/img/logo-runscope-1x.png deleted file mode 100644 index ae3965d..0000000 Binary files a/requestbin/static/img/logo-runscope-1x.png and /dev/null differ diff --git a/requestbin/static/img/logo-runscope-2x.png b/requestbin/static/img/logo-runscope-2x.png deleted file mode 100644 index 4c6a85c..0000000 Binary files a/requestbin/static/img/logo-runscope-2x.png and /dev/null differ diff --git a/requestbin/static/img/runscope-hero.png b/requestbin/static/img/runscope-hero.png deleted file mode 100644 index c916571..0000000 Binary files a/requestbin/static/img/runscope-hero.png and /dev/null differ diff --git a/requestbin/static/less/custom.less b/requestbin/static/less/custom.less index 098f066..ce27372 100644 --- a/requestbin/static/less/custom.less +++ b/requestbin/static/less/custom.less @@ -7,7 +7,7 @@ // -------------------------------------------------- -// Runscope Colors +// Colors // ------------------------- @rsNavy: #061427; @rsRoyal: #1b70e0; diff --git a/requestbin/static/less/styles.less b/requestbin/static/less/styles.less index 64d59e7..a8fdee6 100644 --- a/requestbin/static/less/styles.less +++ b/requestbin/static/less/styles.less @@ -55,7 +55,7 @@ hr { color: @white; } -.runscope-wrap { +.formal-wrap { padding: 4px 20px; background: @grayLightest; border-bottom: 1px solid @grayLighter; diff --git a/requestbin/storage/memory.py b/requestbin/storage/memory.py index 8e8f54b..f66c512 100644 --- a/requestbin/storage/memory.py +++ b/requestbin/storage/memory.py @@ -1,10 +1,10 @@ import time -import operator - from ..models import Bin + from requestbin import config + class MemoryStorage(): cleanup_interval = config.CLEANUP_INTERVAL @@ -18,7 +18,7 @@ def do_start(self): def _cleanup_loop(self): while True: - self.async.sleep(self.cleanup_interval) + self.asynchronous.sleep(self.cleanup_interval) self._expire_bins() def _expire_bins(self): diff --git a/requestbin/storage/redis.py b/requestbin/storage/redis.py index ae0df9a..8207bf7 100644 --- a/requestbin/storage/redis.py +++ b/requestbin/storage/redis.py @@ -1,20 +1,19 @@ from __future__ import absolute_import -import time -import cPickle as pickle - import redis from ..models import Bin from requestbin import config + class RedisStorage(): prefix = config.REDIS_PREFIX def __init__(self, bin_ttl): self.bin_ttl = bin_ttl - self.redis = redis.StrictRedis(host=config.REDIS_HOST, port=config.REDIS_PORT, db=config.REDIS_DB, password=config.REDIS_PASSWORD) + self.redis = redis.StrictRedis( + host=config.REDIS_HOST, port=config.REDIS_PORT, db=config.REDIS_DB, password=config.REDIS_PASSWORD) def _key(self, name): return '{}_{}'.format(self.prefix, name) @@ -56,5 +55,5 @@ def lookup_bin(self, name): bin = Bin.load(serialized_bin) return bin except TypeError: - self.redis.delete(key) # clear bad data + self.redis.delete(key) # clear bad data raise KeyError("Bin not found") diff --git a/requestbin/templates/bin.html b/requestbin/templates/bin.html index c423bdb..4d6ac6b 100644 --- a/requestbin/templates/bin.html +++ b/requestbin/templates/bin.html @@ -142,9 +142,6 @@

Limits

This {% if bin.private %}private{% endif %} bin will keep the last {{MAX_REQUESTS}} requests made to it and remain available for {{BIN_TTL}} hours after it was created. However, data might be cleared at any time, so treat bins as highly ephemeral.

- -

Need more?

-

Sign up for a free Runscope account. Runscope request captures give you live updates, permanent URLs, file handling and much more.

{% endblock %} diff --git a/requestbin/templates/doc.html b/requestbin/templates/doc.html deleted file mode 100644 index 3746210..0000000 --- a/requestbin/templates/doc.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "layout.html" %} -{% block head %} - -{% endblock %} -{% block content %} - - {{content|safe}} -{% endblock %} diff --git a/requestbin/templates/layout.html b/requestbin/templates/layout.html index 3229505..b5fbdc7 100644 --- a/requestbin/templates/layout.html +++ b/requestbin/templates/layout.html @@ -14,16 +14,15 @@ -
+
-

A Runscope community project. Send us feedback!

+

A project on GitHub

- RequestBin

diff --git a/requestbin/util.py b/requestbin/util.py index 4a56c25..07fb9a8 100644 --- a/requestbin/util.py +++ b/requestbin/util.py @@ -2,23 +2,28 @@ import random import base64 + def random_byte(gradient=None, floor=0): factor = gradient or 1 max = int(255 / factor) return random.randint(floor, max) * factor -def solid16x16gif_datauri(r,g,b): + +def solid16x16gif_datauri(r, g, b): return "data:image/gif;base64,R0lGODlhEAAQAIAA%sACH5BAQAAAAALAAAAAAQABAAAAIOhI+py+0Po5y02ouzPgUAOw==" \ - % base64.b64encode(bytearray([0,r,g,b,0,0])) + % base64.b64encode(bytearray([0, r, g, b, 0, 0])) + def random_color(): return random_byte(10, 5), random_byte(10, 5), random_byte(10, 5) -def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"): - return ((num == 0) and "0" ) or (baseN(num // b, b).lstrip("0") + numerals[num % b]) + +def baseN(num, b, numerals="0123456789abcdefghijklmnopqrstuvwxyz"): + return ((num == 0) and "0") or (baseN(num // b, b).lstrip("0") + numerals[num % b]) + def tinyid(size=6): id = '%s%s' % ( - baseN(abs(hash(time.time())), 36), + baseN(abs(hash(time.time())), 36), baseN(abs(hash(time.time())), 36)) return id[0:size] diff --git a/requestbin/views.py b/requestbin/views.py index 4c53a15..5f5375e 100644 --- a/requestbin/views.py +++ b/requestbin/views.py @@ -1,7 +1,8 @@ -import urllib -from flask import session, redirect, url_for, escape, request, render_template, make_response +from flask import make_response, render_template, request, session + +import requestbin.config as config +from requestbin import db -from requestbin import config, app, db def update_recent_bins(name): if 'recent' not in session: @@ -26,40 +27,26 @@ def expand_recent_bins(): session.modified = True return recent -@app.endpoint('views.home') + def home(): return render_template('home.html', recent=expand_recent_bins()) -@app.endpoint('views.bin') def bin(name): try: bin = db.lookup_bin(name) except KeyError: return "Not found\n", 404 - if request.query_string == 'inspect': + if request.query_string.decode() == 'inspect': if bin.private and session.get(bin.name) != bin.secret_key: return "Private bin\n", 403 update_recent_bins(name) return render_template('bin.html', - bin=bin, - base_url=request.scheme+'://'+request.host, - MAX_REQUESTS=config.MAX_REQUESTS, - BIN_TTL=config.BIN_TTL / 3600) + bin=bin, + base_url=request.scheme+'://'+request.host, + MAX_REQUESTS=config.MAX_REQUESTS, + BIN_TTL=config.BIN_TTL / 3600) else: db.create_request(bin, request) resp = make_response("ok\n") - resp.headers['Sponsored-By'] = "https://www.runscope.com" return resp - - -@app.endpoint('views.docs') -def docs(name): - doc = db.lookup_doc(name) - if doc: - return render_template('doc.html', - content=doc['content'], - title=doc['title'], - recent=expand_recent_bins()) - else: - return "Not found", 404 diff --git a/requirements.txt b/requirements.txt index 09ef285..44767e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,9 @@ -gevent ProxyTypes nose -wsgiref feedparser Flask-Cors redis msgpack-python python-dateutil -gunicorn bugsnag blinker diff --git a/runtime.txt b/runtime.txt index 5385682..9bff0e0 100644 --- a/runtime.txt +++ b/runtime.txt @@ -1 +1 @@ -python-2.7.14 +python-3.9.6 diff --git a/setup.py b/setup.py index 3aa6902..3baf46e 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,11 @@ #!/usr/bin/env python -import os from setuptools import setup, find_packages setup( name='requestbin', - version='2.0.0', - author='Runscope', - author_email='requestbin@runscope.com', + version='3.0.0', + author='Cellebyte', + author_email='cellebyte@gmail.com', description='HTTP request collector and inspector', packages=find_packages(), install_requires=['feedparser'], diff --git a/web.py b/web.py index bd9824f..ff8025f 100644 --- a/web.py +++ b/web.py @@ -1,8 +1,7 @@ from requestbin import config -import os -from requestbin import app +from requestbin.app import app if __name__ == "__main__": port = int(config.PORT) - app.run(host='0.0.0.0', port=port, debug=config.DEBUG) \ No newline at end of file + app.run(host='0.0.0.0', port=port, debug=config.DEBUG) diff --git a/wercker.yml b/wercker.yml index d2450e2..3816140 100644 --- a/wercker.yml +++ b/wercker.yml @@ -1,4 +1,4 @@ -box: python:2.7 +box: python:3.8 services: - redis:2.8 build: