Skip to content

Instantly share code, notes, and snippets.

@Mazyod
Created April 3, 2018 15:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mazyod/bcd63906f275cf8ebded653557bb341c to your computer and use it in GitHub Desktop.
Save Mazyod/bcd63906f275cf8ebded653557bb341c to your computer and use it in GitHub Desktop.
Migrating from Flask to Bottle
-import flask
-from werkzeug.http import Headers
+import bottle
[ ... ]
+# Remove "hop-by-hop" headers (as defined by RFC2613, Section 13)
+# since they are not allowed by the WSGI standard.
+FILTER_HEADERS = [
+ 'Connection',
+ 'Keep-Alive',
+ 'Proxy-Authenticate',
+ 'Proxy-Authorization',
+ 'TE',
+ 'Trailers',
+ 'Transfer-Encoding',
+ 'Upgrade',
+]
+
+PROJECT_DIR = os.path.dirname(__file__)
+WEB_ROOT = os.path.join(PROJECT_DIR, "snap-audit", "build")
+STATIC_ROOT = os.path.join(WEB_ROOT, "static")
+
+
[ ... ]
# Server
#
-app = flask.Flask(__name__, static_folder='snap-audit/build')
-
[ ... ]
# global handlers
-@app.errorhandler(400)
+@bottle.error(400)
def bad_request(e):
- return flask.jsonify(error=400, text=str(e)), 400
+ return dict(error=400, text=str(e))
-@app.errorhandler(404)
+@bottle.error(404)
def page_not_found(e):
- return flask.jsonify(error=404, text=str(e)), 404
+ return dict(error=404, text=str(e))
-@app.route('/')
+@bottle.get('/')
def root_path():
- return flask.jsonify(status="ok")
+ return {"status": "ok"}
# mock-server-api
-@app.route('/mock-server-api/mount', methods=["GET", "POST"])
+@bottle.route('/mock-server-api/mount', method="ANY")
def mock_server_mount():
"""Mounts a given postman group
Expected Query: ?group={group_name}
"""
- group = flask.request.args.get("group")
+ group = bottle.request.query.group
if not group:
- flask.abort(400, description="missing query parameter 'group'")
+ bottle.abort(400, "missing query parameter 'group'")
if not mounting_service.push_group(group):
- flask.abort(400, description="group not found")
+ bottle.abort(400, "group not found")
- return flask.jsonify(status="ok")
+ return {"status": "ok"}
-@app.route('/mock-server-api/unmount', methods=["GET", "POST"])
+@bottle.route('/mock-server-api/unmount', method="ANY")
def mock_server_unmount():
"""Unmounts a given postman group, otherwise unmounts all groups.
Expected Query: ?group={group_name}
"""
- group = flask.request.args.get("group")
+ group = bottle.request.query.group
if group:
mounting_service.unmount_group(group)
else:
mounting_service.unmount_all_groups()
- return flask.jsonify(status="ok")
+ return {"status": "ok"}
# mock-server
-@app.route('/mock-server/<path:mock_path>', methods=["GET", "POST", "PUT", "PATCH", "DELETE"])
+@bottle.route('/mock-server/<mock_path:re:.+>', method="ANY")
def mock_server(mock_path):
"""Serves the designated mock postman collection"""
item = mounting_service.item_for(mock_path)
if not item:
- flask.abort(404)
+ bottle.abort(404)
# TODO - perhaps find required example?
response = item.response[0]
jstring = response["body"]
status = response["code"]
# TODO - enable gzip encoding
- ignored_headers = ["Content-Encoding"]
- headers = [h for h in response["header"] if h["key"] not in ignored_headers]
+ headers = [h for h in response["header"] if h["key"] not in FILTER_HEADERS]
+
+ bottle.response.status = status
+ bottle.response.content_type = "application/json"
+
+ for h in headers:
+ bottle.response.set_header(h["key"], h["value"])
- return app.response_class(response=jstring,
- status=status,
- headers=Headers([(h["key"], h["value"]) for h in headers]),
- mimetype="application/json")
+ return jstring
# postman-dump
-@app.route('/postman-dump', methods=["POST"])
+@bottle.post('/postman-dump')
def postman_dump():
"""Postman recording API. Incoming request will be captured into a postman collection
Expected format:
@@ -295,52 +313,64 @@ def postman_dump():
}
}
"""
- capture_service.add(flask.request.json)
- return flask.jsonify(status="ok")
+ capture_service.add(bottle.request.json)
+ return {"status": "ok"}
# snap-audit
-@app.route('/snap-audit', methods=["GET"])
+@bottle.get('/snap-audit')
+@bottle.get('/index.html')
def serve_snap_audit():
"""snap audit is our React.js app"""
- return flask.send_from_directory("snap-audit/build", "index.html")
+ return bottle.static_file("index.html", WEB_ROOT)
+
+
+@bottle.get('/manifest.json')
+def serve_snap_audit():
+ return bottle.static_file("manifest.json", WEB_ROOT)
+
+
+@bottle.get('/service-worker.js')
+def serve_snap_audit():
+ return bottle.static_file("service-worker.js", WEB_ROOT)
-@app.route('/static/<path:path>')
+@bottle.route('/static/<path:re:.+>', method="ANY")
def serve_static_asset(path):
- return flask.send_from_directory('snap-audit/build/static', path)
+ return bottle.static_file(path, STATIC_ROOT)
-@app.route('/snap-audit/test-result', methods=["POST"])
+@bottle.route('/snap-audit/test-result', method="ANY")
def record_test_result():
"""Records the given test result as part of the test metadata
Expected Header: Content-Type: application/json
Expected Query: ?path=feature/variant/environment
Expected Body: {"success": bool}
"""
- path = flask.request.args.get("path")
+ path = bottle.request.query.path
if not path:
- flask.abort(400, description="please provide path query item")
+ bottle.abort(400, "please provide path query item")
- firebase.upload_test_result(path, flask.request.json)
- return flask.jsonify(status="ok")
+ firebase.upload_test_result(path, bottle.request.json)
+ return {"status": "ok"}
-@app.route('/snap-audit/screenshot/upload', methods=["POST", "PUT"])
+@bottle.route('/snap-audit/screenshot/upload', method="ANY")
def upload_screenshot():
"""Uploads the given image asynchronously to our storage service. The reason we ask for arbitrary path variable is
to allow clients to decide their preferred way to structure their screenshots.
Expected Header: Content-Type: image/png
Expected Query: ?path=feature/variant/environment&index=3"""
- path = flask.request.args.get("path")
- index = flask.request.args.get("index")
+ path = bottle.request.query.path
+ index = bottle.request.query.index
if not path or not index:
- flask.abort(400, description="please provide path and index query items")
+ bottle.abort(400, "please provide path and index query items")
- firebase.upload_screenshot(path, index, flask.request.data)
- return flask.jsonify(status="ok")
+ firebase.upload_screenshot(path, index, bottle.request.body.read())
+ return {"status": "ok"}
if __name__ == '__main__':
- app.run(host='0.0.0.0', port=5858)
+ bottle.debug(True)
+ bottle.run(host='0.0.0.0', port=5858)
diff --git a/requirements.txt b/requirements.txt
index be2a752..b78e1e9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,9 +1,8 @@
+bottle==0.12.13
cachetools==2.0.1
certifi==2018.1.18
chardet==3.0.4
-click==6.7
firebase-admin==2.9.1
-Flask==0.12.2
google-api-core==1.1.0
google-auth==1.4.1
google-cloud-core==0.28.1
@@ -12,9 +11,6 @@ google-cloud-storage==1.8.0
google-resumable-media==0.3.1
googleapis-common-protos==1.5.3
idna==2.6
-itsdangerous==0.24
-Jinja2==2.10
-MarkupSafe==1.0
protobuf==3.5.2.post1
pyasn1==0.4.2
pyasn1-modules==0.2.1
@@ -23,4 +19,3 @@ requests==2.18.4
rsa==3.4.2
six==1.11.0
urllib3==1.22
-Werkzeug==0.14.1
--
2.15.1 (Apple Git-101)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment