Mount sub-applications

This commit is contained in:
Miguel Grinberg
2022-07-30 15:44:19 +01:00
parent f1a93ec35e
commit cd5b35d86f
2 changed files with 56 additions and 0 deletions

View File

@@ -543,6 +543,7 @@ class Response():
class URLPattern(): class URLPattern():
def __init__(self, url_pattern): def __init__(self, url_pattern):
self.url_pattern = url_pattern
self.pattern = '' self.pattern = ''
self.args = [] self.args = []
use_regex = False use_regex = False
@@ -798,6 +799,23 @@ class Microdot():
return f return f
return decorated return decorated
def mount(self, subapp, url_prefix=''):
"""Mount a sub-application, optionally under the given URL prefix.
:param subapp: The sub-application to mount.
:param url_prefix: The URL prefix to mount the application under.
"""
for methods, pattern, handler in subapp.url_map:
self.url_map.append(
(methods, URLPattern(url_prefix + pattern.url_pattern),
handler))
for handler in subapp.before_request_handlers:
self.before_request_handlers.append(handler)
for handler in subapp.after_request_handlers:
self.after_request_handlers.append(handler)
for status_code, handler in subapp.error_handlers.items():
self.error_handlers[status_code] = handler
def run(self, host='0.0.0.0', port=5000, debug=False): def run(self, host='0.0.0.0', port=5000, debug=False):
"""Start the web server. This function does not normally return, as """Start the web server. This function does not normally return, as
the server enters an endless listening loop. The :func:`shutdown` the server enters an endless listening loop. The :func:`shutdown`

View File

@@ -309,3 +309,41 @@ class TestMicrodot(unittest.TestCase):
self.assertTrue(fd.response.startswith(b'HTTP/1.0 200 OK\r\n')) self.assertTrue(fd.response.startswith(b'HTTP/1.0 200 OK\r\n'))
self.assertIn(b'Content-Type: text/plain\r\n', fd.response) self.assertIn(b'Content-Type: text/plain\r\n', fd.response)
self.assertTrue(fd.response.endswith(b'\r\n\r\nfoobar')) self.assertTrue(fd.response.endswith(b'\r\n\r\nfoobar'))
def test_mount(self):
subapp = Microdot()
@subapp.before_request
def before(req):
req.g.before = 'before'
@subapp.after_request
def after(req, res):
return res.body + b':after'
@subapp.errorhandler(404)
def not_found(req):
return '404', 404
@subapp.route('/app')
def index(req):
return req.g.before + ':foo'
app = Microdot()
app.mount(subapp, url_prefix='/sub')
mock_socket.clear_requests()
fd = mock_socket.add_request('GET', '/app')
self._add_shutdown(app)
app.run()
self.assertTrue(fd.response.startswith(b'HTTP/1.0 404 N/A\r\n'))
self.assertIn(b'Content-Type: text/plain\r\n', fd.response)
self.assertTrue(fd.response.endswith(b'\r\n\r\n404'))
mock_socket.clear_requests()
fd = mock_socket.add_request('GET', '/sub/app')
self._add_shutdown(app)
app.run()
self.assertTrue(fd.response.startswith(b'HTTP/1.0 200 OK\r\n'))
self.assertIn(b'Content-Type: text/plain\r\n', fd.response)
self.assertTrue(fd.response.endswith(b'\r\n\r\nbefore:foo:after'))