Merge branch 'master' of http://github.com/mitsuhiko/flask
This commit is contained in:
commit
f9c9e31eb8
9 changed files with 490 additions and 37 deletions
5
Makefile
5
Makefile
|
|
@ -1,10 +1,13 @@
|
||||||
.PHONY: clean-pyc test upload-docs docs
|
.PHONY: clean-pyc ext-test test upload-docs docs
|
||||||
|
|
||||||
all: clean-pyc test
|
all: clean-pyc test
|
||||||
|
|
||||||
test:
|
test:
|
||||||
python setup.py test
|
python setup.py test
|
||||||
|
|
||||||
|
ext-test:
|
||||||
|
python tests/flaskext_test.py --browse
|
||||||
|
|
||||||
release:
|
release:
|
||||||
python setup.py release sdist upload
|
python setup.py release sdist upload
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,8 @@ extension to be approved you have to follow these guidelines:
|
||||||
link to the documentation, website (if there is one) and there
|
link to the documentation, website (if there is one) and there
|
||||||
must be a link to automatically install the development version
|
must be a link to automatically install the development version
|
||||||
(``PackageName==dev``).
|
(``PackageName==dev``).
|
||||||
|
9. The ``zip_safe`` flag in the setup scrip must be set to ``False``,
|
||||||
|
even if the extension would be safe for zipping.
|
||||||
|
|
||||||
|
|
||||||
.. _Flask Extension Wizard:
|
.. _Flask Extension Wizard:
|
||||||
|
|
|
||||||
32
extreview/approved.rst
Normal file
32
extreview/approved.rst
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
Approved Extensions
|
||||||
|
===================
|
||||||
|
|
||||||
|
This document contains a list of all extensions that were approved and the
|
||||||
|
date of approval as well as notes. This should make it possible to better
|
||||||
|
track the extension approval process.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Babel
|
||||||
|
-----------
|
||||||
|
|
||||||
|
:First Approval: 2010-07-23
|
||||||
|
:Last Review: 2010-07-23
|
||||||
|
:Approved version: 0.6
|
||||||
|
:Approved license: BSD
|
||||||
|
|
||||||
|
Notes: Developed by the Flask development head
|
||||||
|
|
||||||
|
How to improve: add a better long description to the next release
|
||||||
|
|
||||||
|
|
||||||
|
Flask-SQLAlchemy
|
||||||
|
----------------
|
||||||
|
|
||||||
|
:First Approval: 2010-07-25
|
||||||
|
:Last Review: 2010-07-25
|
||||||
|
:Approved version: 0.9
|
||||||
|
:Approved license: BSD
|
||||||
|
|
||||||
|
Notes: Developed by the Flask development head
|
||||||
|
|
||||||
|
How to improve: add a better long description to the next release
|
||||||
183
extreview/listed.rst
Normal file
183
extreview/listed.rst
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
Listed Extensions
|
||||||
|
=================
|
||||||
|
|
||||||
|
This list contains extensions that passed listing. This means the
|
||||||
|
extension is on the list of extensions on the website. It does not
|
||||||
|
contain extensions that are approved.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-CouchDB
|
||||||
|
-------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed version: 0.2
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test".
|
||||||
|
|
||||||
|
|
||||||
|
Flask-CouchDBKit
|
||||||
|
----------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.2
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test".
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Creole
|
||||||
|
------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.2
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test". Furthermore the README
|
||||||
|
file is empty.
|
||||||
|
|
||||||
|
|
||||||
|
flask-csrf
|
||||||
|
----------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.2
|
||||||
|
|
||||||
|
Will not be approved because this is functionality that should be handled
|
||||||
|
in the form handling systems which is for Flask-WTF already the case.
|
||||||
|
Also, this implementation only supports one open tab with forms.
|
||||||
|
|
||||||
|
Name is not following Flask extension naming rules.
|
||||||
|
|
||||||
|
Considered for unlisting.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Genshi
|
||||||
|
------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.3
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test". Furthermore the long
|
||||||
|
description is empty. The zip_safe flag is not set to False which is a
|
||||||
|
requirement for approved extensions.
|
||||||
|
|
||||||
|
|
||||||
|
flask-lesscss
|
||||||
|
-------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.9.1
|
||||||
|
|
||||||
|
Broken package description, nonconforming package name, does not follow
|
||||||
|
standard API rules (init_lesscss instead of lesscss).
|
||||||
|
|
||||||
|
Considered for unlisting, improved version should release as
|
||||||
|
"Flask-LessCSS" with a conforming API and fixed packages indices, as well
|
||||||
|
as a testsuite.
|
||||||
|
|
||||||
|
|
||||||
|
flask-mail
|
||||||
|
----------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.3.1
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test". Furthermore the long
|
||||||
|
description in the package index is a little bit too short.
|
||||||
|
|
||||||
|
Package name should be changed to Flask-Mail with the approval to be
|
||||||
|
consistent, this might also be the change to improve the API if necessary,
|
||||||
|
but I don't see any big design problems there.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-OAuth
|
||||||
|
-----------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.9
|
||||||
|
|
||||||
|
Short long description, missing tests.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-OpenID
|
||||||
|
------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 1.0.1
|
||||||
|
|
||||||
|
Short long description, missing tests.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Script
|
||||||
|
------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.2
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test".
|
||||||
|
|
||||||
|
The upcoming 0.3 release looks promising, could need a longer "long
|
||||||
|
description" in the package index though.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Testing
|
||||||
|
-------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.2
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test".
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Themes
|
||||||
|
------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.1
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test".
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Uploads
|
||||||
|
-------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.1
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test".
|
||||||
|
|
||||||
|
|
||||||
|
Flask-WTF
|
||||||
|
---------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.2.1
|
||||||
|
|
||||||
|
Would be fine for approval, but the test suite is not part of the sdist
|
||||||
|
package (missing entry in MANIFEST.in) and the test suite does not respond
|
||||||
|
to either "make test" or "python setup.py test".
|
||||||
|
|
||||||
|
|
||||||
|
Flask-XML-RPC
|
||||||
|
-------------
|
||||||
|
|
||||||
|
:Last-Review: 2010-07-25
|
||||||
|
:Reviewed Version: 0.2.1
|
||||||
|
|
||||||
|
Missing tests, API wise it would be fine for approval.
|
||||||
55
extreview/unlisted.rst
Normal file
55
extreview/unlisted.rst
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
Unlisted Extensions
|
||||||
|
===================
|
||||||
|
|
||||||
|
This is a list of extensions that is currently rejected from listing and
|
||||||
|
with that also not approved. If an extension ends up here it should
|
||||||
|
improved to be listed.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Actions
|
||||||
|
-------------
|
||||||
|
|
||||||
|
:Last Review: 2010-07-25
|
||||||
|
:Reviewed version: 0.2
|
||||||
|
|
||||||
|
Rejected because of missing description in PyPI, formatting issues with
|
||||||
|
the documentation (missing headlines, scrollbars etc.) and a general clash
|
||||||
|
of functionality with the Flask-Script package. Latter should not be a
|
||||||
|
problem, but the documentation should improve. For listing, the extension
|
||||||
|
developer should probably discuss the extension on the mailinglist with
|
||||||
|
others.
|
||||||
|
|
||||||
|
Futhermore it also has an egg registered with an invalid filename.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Jinja2Extender
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
:Last Review: 2010-07-25
|
||||||
|
:Reviewed version: 0.1
|
||||||
|
|
||||||
|
Usecase not obvious, hacky implementation, does not solve a problem that
|
||||||
|
could not be solved with Flask itself. I suppose it is to aid other
|
||||||
|
extensions, but that should be discussed on the mailinglist.
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Markdown
|
||||||
|
--------------
|
||||||
|
|
||||||
|
:Last Review: 2010-07-25
|
||||||
|
:Reviewed version: 0.2
|
||||||
|
|
||||||
|
Would be great for enlisting but it should follow the API of Flask-Creole.
|
||||||
|
Besides that, the docstrings are not valid rst (run through rst2html to
|
||||||
|
see the issue) and it is missing tests. Otherwise fine :)
|
||||||
|
|
||||||
|
|
||||||
|
flask-urls
|
||||||
|
----------
|
||||||
|
|
||||||
|
:Last Review: 2010-07-25
|
||||||
|
:Reviewed version: 0.9.2
|
||||||
|
|
||||||
|
Broken PyPI index and non-conforming extension name. Due to the small
|
||||||
|
featureset this was also delisted from the list. It was there previously
|
||||||
|
before the approval process was introduced.
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
|
|
||||||
import os
|
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
@ -20,7 +19,7 @@ from jinja2 import Environment
|
||||||
|
|
||||||
from werkzeug import ImmutableDict
|
from werkzeug import ImmutableDict
|
||||||
from werkzeug.routing import Map, Rule
|
from werkzeug.routing import Map, Rule
|
||||||
from werkzeug.exceptions import HTTPException, InternalServerError, NotFound
|
from werkzeug.exceptions import HTTPException, InternalServerError
|
||||||
|
|
||||||
from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \
|
from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \
|
||||||
_tojson_filter, _endpoint_from_view_func
|
_tojson_filter, _endpoint_from_view_func
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import posixpath
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from time import time
|
from time import time
|
||||||
from zlib import adler32
|
from zlib import adler32
|
||||||
from functools import wraps
|
|
||||||
|
|
||||||
# try to load the best simplejson implementation available. If JSON
|
# try to load the best simplejson implementation available. If JSON
|
||||||
# is not installed, we add a failing class.
|
# is not installed, we add a failing class.
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
:copyright: (c) 2010 by Armin Ronacher.
|
:copyright: (c) 2010 by Armin Ronacher.
|
||||||
:license: BSD, see LICENSE for more details.
|
:license: BSD, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound
|
from jinja2 import BaseLoader, TemplateNotFound
|
||||||
|
|
||||||
from .globals import _request_ctx_stack
|
from .globals import _request_ctx_stack
|
||||||
from .signals import template_rendered
|
from .signals import template_rendered
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,14 @@
|
||||||
|
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
|
|
||||||
import tempfile, subprocess, urllib2, os
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import urllib2
|
||||||
|
import tempfile
|
||||||
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
from cStringIO import StringIO
|
||||||
|
|
||||||
from flask import json
|
from flask import json
|
||||||
|
|
||||||
|
|
@ -19,24 +26,136 @@ from setuptools.package_index import PackageIndex
|
||||||
from setuptools.archive_util import unpack_archive
|
from setuptools.archive_util import unpack_archive
|
||||||
|
|
||||||
flask_svc_url = 'http://flask.pocoo.org/extensions/'
|
flask_svc_url = 'http://flask.pocoo.org/extensions/'
|
||||||
tdir = tempfile.mkdtemp()
|
|
||||||
|
if sys.platform == 'darwin':
|
||||||
|
_tempdir = '/private/tmp'
|
||||||
|
else:
|
||||||
|
_tempdir = tempfile.gettempdir()
|
||||||
|
tdir = _tempdir + '/flaskext-test'
|
||||||
|
flaskdir = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
|
'..'))
|
||||||
|
|
||||||
|
|
||||||
def run_tests(checkout_dir):
|
RESULT_TEMPATE = u'''\
|
||||||
cmd = ['tox']
|
<!doctype html>
|
||||||
return subprocess.call(cmd, cwd=checkout_dir,
|
<title>Flask-Extension Test Results</title>
|
||||||
stdout=open(os.path.join(tdir, 'tox.log'), 'w'),
|
<style type=text/css>
|
||||||
stderr=subprocess.STDOUT)
|
body { font-family: 'Georgia', serif; font-size: 17px; color: #000; }
|
||||||
|
a { color: #004B6B; }
|
||||||
|
a:hover { color: #6D4100; }
|
||||||
|
h1, h2, h3 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; }
|
||||||
|
h1 { font-size: 30px; margin: 15px 0 5px 0; }
|
||||||
|
h2 { font-size: 24px; margin: 15px 0 5px 0; }
|
||||||
|
h3 { font-size: 19px; margin: 15px 0 5px 0; }
|
||||||
|
textarea, code,
|
||||||
|
pre { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono',
|
||||||
|
'Bitstream Vera Sans Mono', monospace!important; font-size: 15px;
|
||||||
|
background: #eee; }
|
||||||
|
pre { padding: 7px 15px; line-height: 1.3; }
|
||||||
|
p { line-height: 1.4; }
|
||||||
|
table { border: 1px solid black; border-collapse: collapse;
|
||||||
|
margin: 15px 0; }
|
||||||
|
td, th { border: 1px solid black; padding: 4px 10px;
|
||||||
|
text-align: left; }
|
||||||
|
th { background: #eee; font-weight: normal; }
|
||||||
|
tr.success { background: #D3F5CC; }
|
||||||
|
tr.failed { background: #F5D2CB; }
|
||||||
|
</style>
|
||||||
|
<h1>Flask-Extension Test Results</h1>
|
||||||
|
<p>
|
||||||
|
This page contains the detailed test results for the test run of
|
||||||
|
all {{ 'approved' if approved }} Flask extensions.
|
||||||
|
<h2>Summary</h2>
|
||||||
|
<table class=results>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Extension
|
||||||
|
<th>Version
|
||||||
|
<th>Author
|
||||||
|
<th>License
|
||||||
|
<th>Outcome
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{%- for result in results %}
|
||||||
|
{% set outcome = 'success' if result.success else 'failed' %}
|
||||||
|
<tr class={{ outcome }}>
|
||||||
|
<th>{{ result.name }}
|
||||||
|
<td>{{ result.version }}
|
||||||
|
<td>{{ result.author }}
|
||||||
|
<td>{{ result.license }}
|
||||||
|
<td>{{ outcome }}
|
||||||
|
</tr>
|
||||||
|
{%- endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h2>Test Logs</h2>
|
||||||
|
<p>Detailed test logs for all tests on all platforms:
|
||||||
|
{%- for result in results %}
|
||||||
|
{%- for iptr, log in result.logs|dictsort %}
|
||||||
|
<h3>{{ result.name }} - {{ result.version }} [{{ iptr }}]</h3>
|
||||||
|
<pre>{{ log }}</pre>
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endfor %}
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def log(msg, *args):
|
||||||
|
print '[EXTTEST]', msg % args
|
||||||
|
|
||||||
|
|
||||||
|
class TestResult(object):
|
||||||
|
|
||||||
|
def __init__(self, name, folder, statuscode, interpreters):
|
||||||
|
intrptr = os.path.join(folder, '.tox/%s/bin/python'
|
||||||
|
% interpreters[0])
|
||||||
|
self.statuscode = statuscode
|
||||||
|
self.folder = folder
|
||||||
|
self.success = statuscode == 0
|
||||||
|
|
||||||
|
def fetch(field):
|
||||||
|
try:
|
||||||
|
c = subprocess.Popen([intrptr, 'setup.py',
|
||||||
|
'--' + field], cwd=folder,
|
||||||
|
stdout=subprocess.PIPE)
|
||||||
|
return c.communicate()[0].strip()
|
||||||
|
except OSError:
|
||||||
|
return '?'
|
||||||
|
self.name = name
|
||||||
|
self.license = fetch('license')
|
||||||
|
self.author = fetch('author')
|
||||||
|
self.version = fetch('version')
|
||||||
|
|
||||||
|
self.logs = {}
|
||||||
|
for interpreter in interpreters:
|
||||||
|
logfile = os.path.join(folder, '.tox/%s/log/test.log'
|
||||||
|
% interpreter)
|
||||||
|
if os.path.isfile(logfile):
|
||||||
|
self.logs[interpreter] = open(logfile).read()
|
||||||
|
else:
|
||||||
|
self.logs[interpreter] = ''
|
||||||
|
|
||||||
|
|
||||||
|
def create_tdir():
|
||||||
|
try:
|
||||||
|
shutil.rmtree(tdir)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
os.mkdir(tdir)
|
||||||
|
|
||||||
|
|
||||||
|
def package_flask():
|
||||||
|
distfolder = tdir + '/.flask-dist'
|
||||||
|
c = subprocess.Popen(['python', 'setup.py', 'sdist', '--formats=gztar',
|
||||||
|
'--dist', distfolder], cwd=flaskdir)
|
||||||
|
c.wait()
|
||||||
|
return os.path.join(distfolder, os.listdir(distfolder)[0])
|
||||||
|
|
||||||
|
|
||||||
def get_test_command(checkout_dir):
|
def get_test_command(checkout_dir):
|
||||||
files = set(os.listdir(checkout_dir))
|
if os.path.isfile(checkout_dir + '/Makefile'):
|
||||||
if 'Makefile' in files:
|
|
||||||
return 'make test'
|
return 'make test'
|
||||||
elif 'conftest.py' in files:
|
return 'python setup.py test'
|
||||||
return 'py.test'
|
|
||||||
else:
|
|
||||||
return 'nosetests'
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_extensions_list():
|
def fetch_extensions_list():
|
||||||
|
|
@ -47,50 +166,111 @@ def fetch_extensions_list():
|
||||||
yield ext
|
yield ext
|
||||||
|
|
||||||
|
|
||||||
def checkout_extension(ext):
|
def checkout_extension(name):
|
||||||
name = ext['name']
|
log('Downloading extension %s to temporary folder', name)
|
||||||
root = os.path.join(tdir, name)
|
root = os.path.join(tdir, name)
|
||||||
os.mkdir(root)
|
os.mkdir(root)
|
||||||
checkout_path = PackageIndex().download(ext['name'], root)
|
checkout_path = PackageIndex().download(name, root)
|
||||||
|
|
||||||
unpack_archive(checkout_path, root)
|
unpack_archive(checkout_path, root)
|
||||||
path = None
|
path = None
|
||||||
for fn in os.listdir(root):
|
for fn in os.listdir(root):
|
||||||
path = os.path.join(root, fn)
|
path = os.path.join(root, fn)
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
break
|
break
|
||||||
|
log('Downloaded to %s', path)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
tox_template = """[tox]
|
tox_template = """[tox]
|
||||||
envlist=py26
|
envlist=%(env)s
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands=
|
deps=%(deps)s
|
||||||
%s
|
commands=bash flaskext-runtest.sh {envlogdir}/test.log
|
||||||
downloadcache=
|
downloadcache=%(cache)s
|
||||||
%s
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def create_tox_ini(checkout_path):
|
|
||||||
|
def create_tox_ini(checkout_path, interpreters, flask_dep):
|
||||||
tox_path = os.path.join(checkout_path, 'tox.ini')
|
tox_path = os.path.join(checkout_path, 'tox.ini')
|
||||||
if not os.path.exists(tox_path):
|
if not os.path.exists(tox_path):
|
||||||
with open(tox_path, 'w') as f:
|
with open(tox_path, 'w') as f:
|
||||||
f.write(tox_template % (get_test_command(checkout_path), tdir))
|
f.write(tox_template % {
|
||||||
|
'env': ','.join(interpreters),
|
||||||
|
'cache': tdir,
|
||||||
|
'deps': flask_dep
|
||||||
|
})
|
||||||
|
|
||||||
# XXX command line
|
|
||||||
only_approved = True
|
|
||||||
|
|
||||||
def test_all_extensions(only_approved=only_approved):
|
def iter_extensions(only_approved=True):
|
||||||
for ext in fetch_extensions_list():
|
for ext in fetch_extensions_list():
|
||||||
if ext['approved'] or not only_approved:
|
if ext['approved'] or not only_approved:
|
||||||
checkout_path = checkout_extension(ext)
|
yield ext['name']
|
||||||
create_tox_ini(checkout_path)
|
|
||||||
ret = run_tests(checkout_path)
|
|
||||||
yield ext['name'], ret
|
def test_extension(name, interpreters, flask_dep):
|
||||||
|
checkout_path = checkout_extension(name)
|
||||||
|
log('Running tests with tox in %s', checkout_path)
|
||||||
|
|
||||||
|
# figure out the test command and write a wrapper script. We
|
||||||
|
# can't write that directly into the tox ini because tox does
|
||||||
|
# not invoke the command from the shell so we have no chance
|
||||||
|
# to pipe the output into a logfile
|
||||||
|
test_command = get_test_command(checkout_path)
|
||||||
|
log('Test command: %s', test_command)
|
||||||
|
f = open(checkout_path + '/flaskext-runtest.sh', 'w')
|
||||||
|
f.write(test_command + ' &> "$1"\n')
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
create_tox_ini(checkout_path, interpreters, flask_dep)
|
||||||
|
rv = subprocess.call(['tox'], cwd=checkout_path)
|
||||||
|
return TestResult(name, checkout_path, rv, interpreters)
|
||||||
|
|
||||||
|
|
||||||
|
def run_tests(interpreters, only_approved=True):
|
||||||
|
results = {}
|
||||||
|
create_tdir()
|
||||||
|
log('Packaging Flask')
|
||||||
|
flask_dep = package_flask()
|
||||||
|
log('Running extension tests')
|
||||||
|
log('Temporary Environment: %s', tdir)
|
||||||
|
for name in iter_extensions(only_approved):
|
||||||
|
log('Testing %s', name)
|
||||||
|
result = test_extension(name, interpreters, flask_dep)
|
||||||
|
if result.success:
|
||||||
|
log('Extension test succeeded')
|
||||||
|
else:
|
||||||
|
log('Extension test failed')
|
||||||
|
results[name] = result
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def render_results(results, approved):
|
||||||
|
from jinja2 import Template
|
||||||
|
items = results.values()
|
||||||
|
items.sort(key=lambda x: x.name.lower())
|
||||||
|
rv = Template(RESULT_TEMPATE, autoescape=True).render(results=items,
|
||||||
|
approved=approved)
|
||||||
|
fd, filename = tempfile.mkstemp(suffix='.html')
|
||||||
|
os.fdopen(fd, 'w').write(rv.encode('utf-8') + '\n')
|
||||||
|
return filename
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
for name, ret in test_all_extensions():
|
parser = argparse.ArgumentParser(description='Runs Flask extension tests')
|
||||||
print name, ret
|
parser.add_argument('--all', dest='all', action='store_true',
|
||||||
|
help='run against all extensions, not just approved')
|
||||||
|
parser.add_argument('--browse', dest='browse', action='store_true',
|
||||||
|
help='show browser with the result summary')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
results = run_tests(['py26'], not args.all)
|
||||||
|
filename = render_results(results, not args.all)
|
||||||
|
if args.browse:
|
||||||
|
import webbrowser
|
||||||
|
webbrowser.open('file:///' + filename.lstrip('/'))
|
||||||
|
print 'Results written to', filename
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue