forked from orbit-oss/flask
Break up a circular dependency on shutdown
This commit is contained in:
parent
11c7b1df23
commit
7f4c12b335
3 changed files with 93 additions and 0 deletions
6
CHANGES
6
CHANGES
|
|
@ -14,6 +14,12 @@ Relase date to be decided, codename to be chosen.
|
||||||
URL rules specific to a given HTTP method.
|
URL rules specific to a given HTTP method.
|
||||||
- Logger now only returns the debug log setting if it was not set
|
- Logger now only returns the debug log setting if it was not set
|
||||||
explicitly.
|
explicitly.
|
||||||
|
- Unregister a circular dependency between the WSGI environment and
|
||||||
|
the request object when shutting down the request. This means that
|
||||||
|
environ ``werkzeug.request`` will be `None` after the response was
|
||||||
|
returned to the WSGI server but has the advantage that the garbage
|
||||||
|
collector is not needed on CPython to tear down the request unless
|
||||||
|
the user created circular dependencies themselves.
|
||||||
|
|
||||||
Version 0.8.1
|
Version 0.8.1
|
||||||
-------------
|
-------------
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,10 @@ class RequestContext(object):
|
||||||
assert rv is self, 'Popped wrong request context. (%r instead of %r)' \
|
assert rv is self, 'Popped wrong request context. (%r instead of %r)' \
|
||||||
% (rv, self)
|
% (rv, self)
|
||||||
|
|
||||||
|
# get rid of circular dependencies at the end of the request
|
||||||
|
# so that we don't require the GC to be active.
|
||||||
|
rv.request.environ['werkzeug.request'] = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.push()
|
self.push()
|
||||||
return self
|
return self
|
||||||
|
|
|
||||||
83
flask/testsuite/regression.py
Normal file
83
flask/testsuite/regression.py
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
flask.testsuite.regression
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests regressions.
|
||||||
|
|
||||||
|
:copyright: (c) 2011 by Armin Ronacher.
|
||||||
|
:license: BSD, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
import gc
|
||||||
|
import sys
|
||||||
|
import flask
|
||||||
|
import threading
|
||||||
|
import unittest
|
||||||
|
from werkzeug.test import run_wsgi_app, create_environ
|
||||||
|
from flask.testsuite import FlaskTestCase
|
||||||
|
|
||||||
|
|
||||||
|
_gc_lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
|
class _NoLeakAsserter(object):
|
||||||
|
|
||||||
|
def __init__(self, testcase):
|
||||||
|
self.testcase = testcase
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
gc.disable()
|
||||||
|
_gc_lock.acquire()
|
||||||
|
loc = flask._request_ctx_stack._local
|
||||||
|
|
||||||
|
# Force Python to track this dictionary at all times.
|
||||||
|
# This is necessary since Python only starts tracking
|
||||||
|
# dicts if they contain mutable objects. It's a horrible,
|
||||||
|
# horrible hack but makes this kinda testable.
|
||||||
|
loc.__storage__['FOOO'] = [1, 2, 3]
|
||||||
|
|
||||||
|
gc.collect()
|
||||||
|
self.old_objects = len(gc.get_objects())
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, tb):
|
||||||
|
if not hasattr(sys, 'getrefcount'):
|
||||||
|
gc.collect()
|
||||||
|
new_objects = len(gc.get_objects())
|
||||||
|
if new_objects > self.old_objects:
|
||||||
|
self.testcase.fail('Example code leaked')
|
||||||
|
_gc_lock.release()
|
||||||
|
gc.enable()
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryTestCase(FlaskTestCase):
|
||||||
|
|
||||||
|
def assert_no_leak(self):
|
||||||
|
return _NoLeakAsserter(self)
|
||||||
|
|
||||||
|
def test_memory_consumption(self):
|
||||||
|
app = flask.Flask(__name__)
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return flask.render_template('simple_template.html', whiskey=42)
|
||||||
|
|
||||||
|
def fire():
|
||||||
|
with app.test_client() as c:
|
||||||
|
rv = c.get('/')
|
||||||
|
self.assert_equal(rv.status_code, 200)
|
||||||
|
self.assert_equal(rv.data, '<h1>42</h1>')
|
||||||
|
|
||||||
|
# Trigger caches
|
||||||
|
fire()
|
||||||
|
|
||||||
|
with self.assert_no_leak():
|
||||||
|
for x in xrange(10):
|
||||||
|
fire()
|
||||||
|
|
||||||
|
|
||||||
|
def suite():
|
||||||
|
suite = unittest.TestSuite()
|
||||||
|
suite.addTest(unittest.makeSuite(MemoryTestCase))
|
||||||
|
return suite
|
||||||
Loading…
Add table
Add a link
Reference in a new issue