Skip to content

Commit

Permalink
Minimal port of tests from bottle to flask
Browse files Browse the repository at this point in the history
Bottle is not Python 3.13+ ready, see bottlepy/bottle#1403

In Fedora, we need pycurl to be able to use fedpkg, our tool for building Fedora packages.

I plan to use this patch in Fedora temporarily until the bottle situation is resolved.
  • Loading branch information
hroncok committed Apr 24, 2024
1 parent 5f66204 commit 79389ae
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 54 deletions.
4 changes: 1 addition & 3 deletions requirements-dev.txt
@@ -1,7 +1,5 @@
# bottle 0.12.17 changed behavior
# https://github.com/pycurl/pycurl/issues/573
bottle
flaky
flask
pyflakes
pytest>=5
sphinx
Expand Down
83 changes: 35 additions & 48 deletions tests/app.py
Expand Up @@ -2,15 +2,15 @@
# vi:ts=4:et

import time as _time, sys
import bottle
import flask
try:
import json
except ImportError:
import simplejson as json

py3 = sys.version_info[0] == 3

app = bottle.Bottle()
app = flask.Flask(__name__)
app.debug = True

@app.route('/success')
Expand All @@ -24,62 +24,47 @@ def short_wait():

@app.route('/status/403')
def forbidden():
return bottle.HTTPResponse('forbidden', 403)
return flask.Response('forbidden', 403)

@app.route('/status/404')
def not_found():
return bottle.HTTPResponse('not found', 404)
return flask.Response('not found', 404)

@app.route('/postfields', method='get')
@app.route('/postfields', method='post')
@app.route('/postfields', methods=['GET', 'POST'])
def postfields():
return json.dumps(dict(bottle.request.forms))
return json.dumps(dict(flask.request.form))

@app.route('/raw_utf8', method='post')
@app.route('/raw_utf8', methods=['POST'])
def raw_utf8():
data = bottle.request.body.getvalue().decode('utf8')
data = flask.request.data.decode('utf8')
return json.dumps(data)

# XXX file is not a bottle FileUpload instance, but FieldStorage?
def xconvert_file(key, file):
return {
'key': key,
'name': file.name,
'raw_filename': file.raw_filename,
'filename': file.filename,
'headers': file.headers,
'content_type': file.content_type,
'content_length': file.content_length,
'data': file.read(),
}

if hasattr(bottle, 'FileUpload'):
# bottle 0.12
def convert_file(key, file):
return {
'name': file.name,
# file.filename lowercases the file name
# https://github.com/defnull/bottle/issues/582
# raw_filenames is a string on python 3
'filename': file.raw_filename,
'data': file.file.read().decode(),
}
else:
# bottle 0.11
def convert_file(key, file):
return {
'name': file.name,
'filename': file.filename,
'data': file.file.read().decode(),
}

@app.route('/files', method='post')
def convert_file(key, file):
return {
'name': file.name,
'filename': file.filename,
'data': file.read().decode(),
}

@app.route('/files', methods=['POST'])
def files():
files = [convert_file(key, bottle.request.files[key]) for key in bottle.request.files]
files = [convert_file(key, flask.request.files[key]) for key in flask.request.files]
return json.dumps(files)

@app.route('/header')
def header():
return bottle.request.headers.get(bottle.request.query['h'], '')
return flask.request.headers.get(flask.request.args['h'], '')

# This is a hacky endpoint to test non-ascii text being given to libcurl
# via headers.
Expand All @@ -89,7 +74,7 @@ def header():
# Thanks to bdarnell for the idea: https://github.com/pycurl/pycurl/issues/124
@app.route('/header_utf8')
def header_utf8():
header_value = bottle.request.headers.get(bottle.request.query['h'], '' if py3 else b'')
header_value = flask.request.headers.get(flask.request.args['h'], '' if py3 else b'')
if py3:
# header_value is a string, headers are decoded in latin1
header_value = header_value.encode('latin1').decode('utf8')
Expand All @@ -98,13 +83,9 @@ def header_utf8():
header_value = header_value.decode('utf8')
return header_value

@app.route('/param_utf8_hack', method='post')
@app.route('/param_utf8_hack', methods=['POST'])
def param_utf8_hack():
param = bottle.request.forms['p']
if py3:
# python 3 decodes bytes as latin1 perhaps?
# apply the latin1-utf8 hack
param = param.encode('latin').decode('utf8')
param = flask.request.form['p']
return param

def pause_writer(interval):
Expand All @@ -127,19 +108,25 @@ def utf8_body():

@app.route('/invalid_utf8_body')
def invalid_utf8_body():
# bottle encodes the body
raise bottle.HTTPResponse(b'\xb3\xd2\xda\xcd\xd7', 200)
return flask.Response(b'\xb3\xd2\xda\xcd\xd7', 200)

@app.route('/set_cookie_invalid_utf8')
def set_cookie_invalid_utf8():
bottle.response.set_header('Set-Cookie', '\xb3\xd2\xda\xcd\xd7=%96%A6g%9Ay%B0%A5g%A7tm%7C%95%9A')
return 'cookie set'
response = flask.Response('cookie set')
# WARNING: The original bottle test passed '\xb3\xd2\xda\xcd\xd7...' as string
# Presumably bottle encoded that as utf-8 in the response.
# Flask on the other hand encodes such strings as latin-1 (chars in == bytes out).
# In order to make the test pass I replicate the original bottle behavior by utf-8->latin1 roundtrip.
response.headers['Set-Cookie'] = '\xb3\xd2\xda\xcd\xd7=%96%A6g%9Ay%B0%A5g%A7tm%7C%95%9A'.encode('utf-8').decode('latin-1')
return response

@app.route('/content_type_invalid_utf8')
def content_type_invalid_utf8():
bottle.response.set_header('Content-Type', '\xb3\xd2\xda\xcd\xd7')
return 'content type set'
response = flask.Response('content type set')
# See the WARNING in set_cookie_invalid_utf8
response.headers['Content-Type'] = '\xb3\xd2\xda\xcd\xd7'.encode('utf-8').decode('latin-1')
return response

@app.route('/status_invalid_utf8')
def status_invalid_utf8():
raise bottle.HTTPResponse('status set', '555 \xb3\xd2\xda\xcd\xd7')
raise flask.Response('status set', b'555 \xb3\xd2\xda\xcd\xd7')
12 changes: 9 additions & 3 deletions tests/runwsgi.py
@@ -1,14 +1,20 @@
# Run a WSGI application in a daemon thread

import bottle
import threading
import os.path

from . import util

global_stop = False

class Server(bottle.WSGIRefServer):
class Server:
quiet = False

def __init__(self, host, port, **options):
self.options = options
self.host = host
self.port = int(port)

def run(self, handler): # pragma: no cover
self.srv = self.make_server(handler)
self.serve()
Expand Down Expand Up @@ -66,7 +72,7 @@ def __init__(self, app, port, server, server_kwargs):
self.server = server(host='127.0.0.1', port=self.port, **self.server_kwargs)

def run(self):
bottle.run(self.app, server=self.server, quiet=True)
self.server.run(self.app)

started_servers = {}

Expand Down

0 comments on commit 79389ae

Please sign in to comment.