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.
|
||||
- Logger now only returns the debug log setting if it was not set
|
||||
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
|
||||
-------------
|
||||
|
|
|
|||
|
|
@ -150,6 +150,10 @@ class RequestContext(object):
|
|||
assert rv is self, 'Popped wrong request context. (%r instead of %r)' \
|
||||
% (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):
|
||||
self.push()
|
||||
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