Browse Source

Merge remote-tracking branch 'upstream/master' into imp_blueprint_static_folders

pull/1339/head
Guillem Julià Blasi 10 years ago
parent
commit
838c976579
  1. 3
      AUTHORS
  2. 16
      docs/signals.rst
  3. 2
      flask/__init__.py
  4. 8
      flask/helpers.py
  5. 160
      scripts/flaskext_migrate.py
  6. 71
      scripts/test_import_migration.py
  7. 14
      setup.py
  8. 16
      tests/test_basic.py
  9. 1
      tox.ini

3
AUTHORS

@ -15,10 +15,12 @@ Patches and Suggestions
- Chris Grindstaff
- Christopher Grebs
- Daniel Neuhäuser
- Edmond Burnett
- Florent Xicluna
- Georg Brandl
- Justin Quick
- Kenneth Reitz
- Keyan Pishdadian
- Marian Sigler
- Matt Campell
- Matthew Frazier
@ -29,4 +31,3 @@ Patches and Suggestions
- Stephane Wirtel
- Thomas Schranz
- Zhao Xiaohong
- Edmond Burnett

16
docs/signals.rst

@ -26,7 +26,7 @@ early by returning a response. In contrast all signal handlers are
executed in undefined order and do not modify any data.
The big advantage of signals over handlers is that you can safely
subscribe to them for the split of a second. These temporary
subscribe to them for just a split second. These temporary
subscriptions are helpful for unittesting for example. Say you want to
know what templates were rendered as part of a request: signals allow you
to do exactly that.
@ -42,11 +42,11 @@ signal, you can use the :meth:`~blinker.base.Signal.disconnect` method.
For all core Flask signals, the sender is the application that issued the
signal. When you subscribe to a signal, be sure to also provide a sender
unless you really want to listen for signals of all applications. This is
unless you really want to listen for signals from all applications. This is
especially true if you are developing an extension.
Here for example a helper context manager that can be used to figure out
in a unittest which templates were rendered and what variables were passed
For example, here is a helper context manager that can be used in a unittest
to determine which templates were rendered and what variables were passed
to the template::
from flask import template_rendered
@ -82,10 +82,10 @@ variable. Whenever a template is rendered, the template object as well as
context are appended to it.
Additionally there is a convenient helper method
(:meth:`~blinker.base.Signal.connected_to`). that allows you to
(:meth:`~blinker.base.Signal.connected_to`) that allows you to
temporarily subscribe a function to a signal with a context manager on
its own. Because the return value of the context manager cannot be
specified that way one has to pass the list in as argument::
specified that way, you have to pass the list in as an argument::
from flask import template_rendered
@ -208,8 +208,8 @@ The following signals exist in Flask:
.. data:: flask.request_started
:noindex:
This signal is sent before any request processing started but when the
request context was set up. Because the request context is already
This signal is sent when the request context is set up, before
any request processing happens. Because the request context is already
bound, the subscriber can access the request with the standard global
proxies such as :class:`~flask.request`.

2
flask/__init__.py

@ -10,7 +10,7 @@
:license: BSD, see LICENSE for more details.
"""
__version__ = '0.11-dev'
__version__ = '0.11.dev0'
# utilities we import from Werkzeug and Jinja2 that are unused
# in the module but are exported as public interface.

8
flask/helpers.py

@ -427,12 +427,8 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
guessing requires a `filename` or an `attachment_filename` to be
provided.
Please never pass filenames to this function from user sources without
checking them first. Something like this is usually sufficient to
avoid security problems::
if '..' in filename or filename.startswith('/'):
abort(404)
Please never pass filenames to this function from user sources;
you should use :func:`send_from_directory` instead.
.. versionadded:: 0.2

160
scripts/flaskext_migrate.py

@ -0,0 +1,160 @@
# Script which modifies source code away from the deprecated "flask.ext"
# format.
#
# Run in the terminal by typing: `python flaskext_migrate.py <source_file.py>`
#
# Author: Keyan Pishdadian 2015
from redbaron import RedBaron
import sys
def read_source(input_file):
"""Parses the input_file into a RedBaron FST."""
with open(input_file, "r") as source_code:
red = RedBaron(source_code.read())
return red
def write_source(red, input_file):
"""Overwrites the input_file once the FST has been modified."""
with open(input_file, "w") as source_code:
source_code.write(red.dumps())
def fix_imports(red):
"""Wrapper which fixes "from" style imports and then "import" style."""
red = fix_standard_imports(red)
red = fix_from_imports(red)
return red
def fix_from_imports(red):
"""
Converts "from" style imports to not use "flask.ext".
Handles:
Case 1: from flask.ext.foo import bam --> from flask_foo import bam
Case 2: from flask.ext import foo --> import flask_foo as foo
"""
from_imports = red.find_all("FromImport")
for x, node in enumerate(from_imports):
values = node.value
if (values[0].value == 'flask') and (values[1].value == 'ext'):
# Case 1
if len(node.value) == 3:
package = values[2].value
modules = node.modules()
module_string = _get_modules(modules)
if len(modules) > 1:
node.replace("from flask_%s import %s"
% (package, module_string))
else:
name = node.names()[0]
node.replace("from flask_%s import %s as %s"
% (package, module_string, name))
# Case 2
else:
module = node.modules()[0]
node.replace("import flask_%s as %s"
% (module, module))
return red
def fix_standard_imports(red):
"""
Handles import modification in the form:
import flask.ext.foo" --> import flask_foo
"""
imports = red.find_all("ImportNode")
for x, node in enumerate(imports):
try:
if (node.value[0].value[0].value == 'flask' and
node.value[0].value[1].value == 'ext'):
package = node.value[0].value[2].value
name = node.names()[0].split('.')[-1]
if name == package:
node.replace("import flask_%s" % (package))
else:
node.replace("import flask_%s as %s" % (package, name))
except IndexError:
pass
return red
def _get_modules(module):
"""
Takes a list of modules and converts into a string.
The module list can include parens, this function checks each element in
the list, if there is a paren then it does not add a comma before the next
element. Otherwise a comma and space is added. This is to preserve module
imports which are multi-line and/or occur within parens. While also not
affecting imports which are not enclosed.
"""
modules_string = [cur + ', ' if cur.isalnum() and next.isalnum()
else cur
for (cur, next) in zip(module, module[1:]+[''])]
return ''.join(modules_string)
def fix_function_calls(red):
"""
Modifies function calls in the source to reflect import changes.
Searches the AST for AtomtrailerNodes and replaces them.
"""
atoms = red.find_all("Atomtrailers")
for x, node in enumerate(atoms):
try:
if (node.value[0].value == 'flask' and
node.value[1].value == 'ext'):
params = _form_function_call(node)
node.replace("flask_%s%s" % (node.value[2], params))
except IndexError:
pass
return red
def _form_function_call(node):
"""
Reconstructs function call strings when making attribute access calls.
"""
node_vals = node.value
output = "."
for x, param in enumerate(node_vals[3::]):
if param.dumps()[0] == "(":
output = output[0:-1] + param.dumps()
return output
else:
output += param.dumps() + "."
def check_user_input():
"""Exits and gives error message if no argument is passed in the shell."""
if len(sys.argv) < 2:
sys.exit("No filename was included, please try again.")
def fix_tester(ast):
"""Wrapper which allows for testing when not running from shell."""
ast = fix_imports(ast)
ast = fix_function_calls(ast)
return ast.dumps()
def fix():
"""Wrapper for user argument checking and import fixing."""
check_user_input()
input_file = sys.argv[1]
ast = read_source(input_file)
ast = fix_imports(ast)
ast = fix_function_calls(ast)
write_source(ast, input_file)
if __name__ == "__main__":
fix()

71
scripts/test_import_migration.py

@ -0,0 +1,71 @@
# Tester for the flaskext_migrate.py module located in flask/scripts/
#
# Author: Keyan Pishdadian
import pytest
from redbaron import RedBaron
import flaskext_migrate as migrate
def test_simple_from_import():
red = RedBaron("from flask.ext import foo")
output = migrate.fix_tester(red)
assert output == "import flask_foo as foo"
def test_from_to_from_import():
red = RedBaron("from flask.ext.foo import bar")
output = migrate.fix_tester(red)
assert output == "from flask_foo import bar as bar"
def test_multiple_import():
red = RedBaron("from flask.ext.foo import bar, foobar, something")
output = migrate.fix_tester(red)
assert output == "from flask_foo import bar, foobar, something"
def test_multiline_import():
red = RedBaron("from flask.ext.foo import \
bar,\
foobar,\
something")
output = migrate.fix_tester(red)
assert output == "from flask_foo import bar, foobar, something"
def test_module_import():
red = RedBaron("import flask.ext.foo")
output = migrate.fix_tester(red)
assert output == "import flask_foo"
def test_named_module_import():
red = RedBaron("import flask.ext.foo as foobar")
output = migrate.fix_tester(red)
assert output == "import flask_foo as foobar"
def test__named_from_import():
red = RedBaron("from flask.ext.foo import bar as baz")
output = migrate.fix_tester(red)
assert output == "from flask_foo import bar as baz"
def test_parens_import():
red = RedBaron("from flask.ext.foo import (bar, foo, foobar)")
output = migrate.fix_tester(red)
assert output == "from flask_foo import (bar, foo, foobar)"
def test_function_call_migration():
red = RedBaron("flask.ext.foo(var)")
output = migrate.fix_tester(red)
assert output == "flask_foo(var)"
def test_nested_function_call_migration():
red = RedBaron("import flask.ext.foo\n\n"
"flask.ext.foo.bar(var)")
output = migrate.fix_tester(red)
assert output == ("import flask_foo\n\n"
"flask_foo.bar(var)")

14
setup.py

@ -42,13 +42,21 @@ Links
<http://github.com/mitsuhiko/flask/zipball/master#egg=Flask-dev>`_
"""
from __future__ import print_function
from setuptools import Command, setup
import re
import ast
from setuptools import setup
_version_re = re.compile(r'__version__\s+=\s+(.*)')
with open('flask/__init__.py', 'rb') as f:
version = str(ast.literal_eval(_version_re.search(
f.read().decode('utf-8')).group(1)))
setup(
name='Flask',
version='0.11-dev',
version=version,
url='http://github.com/mitsuhiko/flask/',
license='BSD',
author='Armin Ronacher',

16
tests/test_basic.py

@ -580,17 +580,27 @@ def test_request_preprocessing_early_return():
evts = []
@app.before_request
def before_request():
def before_request1():
evts.append(1)
@app.before_request
def before_request2():
evts.append(2)
return "hello"
@app.before_request
def before_request3():
evts.append(3)
return "bye"
@app.route('/')
def index():
evts.append('index')
return "damnit"
rv = app.test_client().get('/').data.strip()
assert rv == 'hello'
assert not evts
assert rv == b'hello'
assert evts == [1, 2]
def test_after_request_processing():

1
tox.ini

@ -8,6 +8,7 @@ commands =
deps=
pytest
greenlet
redbaron
lowest: Werkzeug==0.7
lowest: Jinja2==2.4

Loading…
Cancel
Save