Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add support for Python 3.3, drop support for 2.5

  • Loading branch information...
commit 3accc62b0b6a79a266feacb2f5c9f63ebf85943d 1 parent 96b56f3
@SimonSapin authored
View
2  .travis.yml
@@ -1,9 +1,9 @@
language: python
python:
- - "2.5"
- "2.6"
- "2.7"
+ - "3.3"
- "pypy"
install:
View
1  docs/conf.py
@@ -11,7 +11,6 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-from __future__ import with_statement
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
View
50 flask_frozen/__init__.py
@@ -12,17 +12,13 @@
"""
-from __future__ import with_statement
-
__all__ = ['Freezer', 'walk_directory', 'relative_url_for']
-VERSION = '0.10'
+VERSION = '0.11'
import os.path
import mimetypes
-import urlparse
-import urllib
import warnings
import collections
import posixpath
@@ -30,36 +26,23 @@
from unicodedata import normalize
from threading import Lock
from contextlib import contextmanager
+from collections import Mapping
+from posixpath import relpath as posix_relpath
+try:
+ from urllib import unquote
+ from urlparse import urlsplit
+except ImportError: # Python 3
+ from urllib.parse import urlsplit, unquote
from werkzeug.exceptions import HTTPException
from flask import (Flask, Blueprint, url_for, request, send_from_directory,
redirect)
try:
- from collections import Mapping
- def is_mapping(obj):
- return isinstance(obj, Mapping)
-except ImportError:
- # Python 2.5, no Abstract Base Classes. Default to duck-typing.
- def is_mapping(obj):
- return hasattr(obj, 'keys')
-
-try:
- from posixpath import relpath as posix_relpath
-except ImportError:
- # Python 2.5
- def posix_relpath(path, start):
- sep = posixpath.sep
- start_list = [x for x in posixpath.abspath(start).split(sep) if x]
- path_list = [x for x in posixpath.abspath(path).split(sep) if x]
-
- # Work out how much of the filepath is shared by start and path.
- i = len(posixpath.commonprefix([start_list, path_list]))
-
- rel_list = [posixpath.pardir] * (len(start_list)-i) + path_list[i:]
- if not rel_list:
- return posixpath.curdir
- return posixpath.join(*rel_list)
+ unicode
+except NameError: # Python 3
+ unicode = str
+ basestring = str
class MissingURLGeneratorWarning(Warning):
@@ -195,7 +178,7 @@ def _script_name(self):
Return the path part of FREEZER_BASE_URL, without trailing slash.
"""
base_url = self.app.config['FREEZER_BASE_URL']
- return urlparse.urlsplit(base_url).path.rstrip('/')
+ return urlsplit(base_url).path.rstrip('/')
def _generate_all_urls(self):
"""
@@ -213,7 +196,7 @@ def _generate_all_urls(self):
url = generated
endpoint = None
else:
- if is_mapping(generated):
+ if isinstance(generated, Mapping):
values = generated
# The endpoint defaults to the name of the
# generator function, just like with Flask views.
@@ -229,8 +212,8 @@ def _generate_all_urls(self):
)
url = url[len(script_name):]
# flask.url_for "quotes" URLs, eg. a space becomes %20
- url = urllib.unquote(url)
- parsed_url = urlparse.urlsplit(url)
+ url = unquote(url)
+ parsed_url = urlsplit(url)
if parsed_url.scheme or parsed_url.netloc:
raise ValueError('External URLs not supported: ' + url)
@@ -317,6 +300,7 @@ def _build_one(self, url):
with open(filename, 'wb') as fd:
fd.write(content)
+ response.close()
return filename
def urlpath_to_filepath(self, path):
View
2  flask_frozen/test_app/__init__.py
@@ -10,8 +10,6 @@
"""
-from __future__ import with_statement
-
import os.path
from functools import partial
View
124 flask_frozen/tests.py
@@ -10,8 +10,6 @@
"""
-from __future__ import with_statement
-
import unittest
import tempfile
import shutil
@@ -20,39 +18,16 @@
import hashlib
from contextlib import contextmanager
from unicodedata import normalize
+from warnings import catch_warnings
from flask_frozen import (Freezer, walk_directory,
MissingURLGeneratorWarning, MimetypeMismatchWarning)
from flask_frozen import test_app
-
try:
- # Python 2.6+
- from warnings import catch_warnings
-except ImportError:
- # Python 2.5
- class WarningMessage(object):
- def __init__(self, message, category, *args, **kwargs):
- self.message = message
- self.category = category
-
- @contextmanager
- def catch_warnings(record=False):
- assert record, 'record=False is not supported'
-
- _filters = warnings.filters
- warnings.filters = _filters[:]
- _showwarning = warnings.showwarning
- log = []
- def showwarning(*args, **kwargs):
- log.append(WarningMessage(*args, **kwargs))
- warnings.showwarning = showwarning
-
- try:
- yield log
- finally:
- warnings.filters = _filters
- warnings.showwarning = _showwarning
+ unicode
+except NameError: # Python 3
+ unicode = str
@contextmanager
@@ -112,7 +87,7 @@ def test_writing(self):
class TestWalkDirectory(unittest.TestCase):
def test_walk_directory(self):
- self.assertEquals(
+ self.assertEqual(
set(f for f in walk_directory(os.path.dirname(test_app.__file__))
if not f.endswith(('.pyc', '.pyo'))),
set(['__init__.py', 'static/style.css', 'static/favicon.ico',
@@ -124,23 +99,23 @@ def test_walk_directory(self):
class TestFreezer(unittest.TestCase):
# URL -> expected bytes content of the generated file
expected_output = {
- u'/': 'Main index /product_5/?revision=b12ef20',
- u'/admin/': 'Admin index\n'
- '<a href="/page/I%20l%C3%B8v%C3%AB%20Unicode/">Unicode test</a>\n'
- '<a href="/page/octothorp/?query_foo=bar#introduction">'
- 'URL parsing test</a>',
- u'/robots.txt': 'User-agent: *\nDisallow: /',
+ u'/': b'Main index /product_5/?revision=b12ef20',
+ u'/admin/': b'Admin index\n'
+ b'<a href="/page/I%20l%C3%B8v%C3%AB%20Unicode/">Unicode test</a>\n'
+ b'<a href="/page/octothorp/?query_foo=bar#introduction">'
+ b'URL parsing test</a>',
+ u'/robots.txt': b'User-agent: *\nDisallow: /',
u'/favicon.ico': read_file(test_app.FAVICON),
- u'/product_0/': 'Product num 0',
- u'/product_1/': 'Product num 1',
- u'/product_2/': 'Product num 2',
- u'/product_3/': 'Product num 3',
- u'/product_4/': 'Product num 4',
- u'/product_5/': 'Product num 5',
+ u'/product_0/': b'Product num 0',
+ u'/product_1/': b'Product num 1',
+ u'/product_2/': b'Product num 2',
+ u'/product_3/': b'Product num 3',
+ u'/product_4/': b'Product num 4',
+ u'/product_5/': b'Product num 5',
u'/static/favicon.ico': read_file(test_app.FAVICON),
- u'/static/style.css': '/* Main CSS */\n',
- u'/admin/css/style.css': '/* Admin CSS */\n',
- u'/where_am_i/': '/where_am_i/ http://localhost/where_am_i/',
+ u'/static/style.css': b'/* Main CSS */\n',
+ u'/admin/css/style.css': b'/* Admin CSS */\n',
+ u'/where_am_i/': b'/where_am_i/ http://localhost/where_am_i/',
u'/page/foo/': u'Hello\xa0World! foo'.encode('utf8'),
u'/page/I løvë Unicode/':
u'Hello\xa0World! I løvë Unicode'.encode('utf8'),
@@ -201,7 +176,7 @@ def assertFilenamesEqual(self, set1, set2):
# Fix for https://github.com/SimonSapin/Frozen-Flask/issues/5
set1 = sorted(normalize('NFC', name) for name in set1)
set2 = sorted(normalize('NFC', name) for name in set2)
- self.assertEquals(set1, set2)
+ self.assertEqual(set1, set2)
def test_without_app(self):
freezer = Freezer()
@@ -215,21 +190,21 @@ def test_all_urls_method(self):
if url in expected:
expected.remove(url)
# Do not use set() here: also test that URLs are not duplicated.
- self.assertEquals(sorted(freezer.all_urls()), expected)
+ self.assertEqual(sorted(freezer.all_urls()), expected)
def test_built_urls(self):
with self.built_app() as (temp, app, freezer, urls):
- self.assertEquals(set(urls), set(self.expected_output))
+ self.assertEqual(set(urls), set(self.expected_output))
# Make sure it was not accidently used as a destination
default = os.path.join(os.path.dirname(__file__), 'build')
- self.assert_(not os.path.exists(default))
+ self.assertTrue(not os.path.exists(default))
def test_contents(self):
with self.built_app() as (temp, app, freezer, urls):
- for url, filename in self.filenames.iteritems():
+ for url, filename in self.filenames.items():
filename = os.path.join(freezer.root, *filename.split('/'))
content = read_file(filename)
- self.assertEquals(content, self.expected_output[url])
+ self.assertEqual(content, self.expected_output[url])
def test_nothing_else_matters(self):
self._extra_files(removed=True)
@@ -246,7 +221,7 @@ def _extra_files(self, removed, remove_extra=True, ignore=()):
app.config['FREEZER_REMOVE_EXTRA_FILES'] = remove_extra
app.config['FREEZER_DESTINATION_IGNORE'] = ignore
dest = unicode(app.config['FREEZER_DESTINATION'])
- expected_files = set(self.filenames.itervalues())
+ expected_files = set(self.filenames.values())
# No other files
self.assertFilenamesEqual(walk_directory(dest), expected_files)
@@ -260,9 +235,9 @@ def _extra_files(self, removed, remove_extra=True, ignore=()):
exists = os.path.exists(os.path.join(dest, 'extra'))
if removed:
- self.assert_(not exists)
+ self.assertTrue(not exists)
else:
- self.assert_(exists)
+ self.assertTrue(exists)
expected_files.add(u'extra/extra.txt')
self.assertFilenamesEqual(walk_directory(dest), expected_files)
@@ -274,10 +249,10 @@ def test_transitivity(self):
app2.config['FREEZER_DESTINATION'] = temp2
app2.debug = True
freezer2 = Freezer(app2)
- freezer2.register_generator(self.filenames.iterkeys)
+ freezer2.register_generator(self.filenames.keys)
freezer2.freeze()
destination = app.config['FREEZER_DESTINATION']
- self.assertEquals(read_all(destination), read_all(temp2))
+ self.assertEqual(read_all(destination), read_all(temp2))
def test_error_on_external_url(self):
for url in ['http://example.com/foo', '//example.com/foo',
@@ -289,7 +264,7 @@ def external_url():
try:
freezer.freeze()
- except ValueError, e:
+ except ValueError as e:
assert 'External URLs not supported' in e.args[0]
else:
assert False, 'Expected ValueError'
@@ -304,8 +279,8 @@ def external_url(some_argument):
with catch_warnings(record=True) as logged_warnings:
warnings.simplefilter("always")
freezer.freeze()
- self.assertEquals(len(logged_warnings), 1)
- self.assertEquals(logged_warnings[0].category,
+ self.assertEqual(len(logged_warnings), 1)
+ self.assertEqual(logged_warnings[0].category,
MissingURLGeneratorWarning)
def test_wrong_default_mimetype(self):
@@ -317,8 +292,8 @@ def no_extension():
with catch_warnings(record=True) as logged_warnings:
warnings.simplefilter("always")
freezer.freeze()
- self.assertEquals(len(logged_warnings), 1)
- self.assertEquals(logged_warnings[0].category,
+ self.assertEqual(len(logged_warnings), 1)
+ self.assertEqual(logged_warnings[0].category,
MimetypeMismatchWarning)
def test_default_mimetype(self):
@@ -352,8 +327,8 @@ def no_extension():
with catch_warnings(record=True) as logged_warnings:
warnings.simplefilter("always")
freezer.freeze()
- self.assertEquals(len(logged_warnings), 1)
- self.assertEquals(logged_warnings[0].category,
+ self.assertEqual(len(logged_warnings), 1)
+ self.assertEqual(logged_warnings[0].category,
MimetypeMismatchWarning)
@@ -363,13 +338,14 @@ class TestInitApp(TestFreezer):
class TestBaseURL(TestFreezer):
expected_output = TestFreezer.expected_output.copy()
- expected_output['/'] = 'Main index /myapp/product_5/?revision=b12ef20'
+ expected_output['/'] = b'Main index /myapp/product_5/?revision=b12ef20'
expected_output['/where_am_i/'] = \
- '/myapp/where_am_i/ http://example/myapp/where_am_i/'
- expected_output['/admin/'] = ('Admin index\n'
- '<a href="/myapp/page/I%20l%C3%B8v%C3%AB%20Unicode/">Unicode test</a>\n'
- '<a href="/myapp/page/octothorp/?query_foo=bar#introduction">'
- 'URL parsing test</a>')
+ b'/myapp/where_am_i/ http://example/myapp/where_am_i/'
+ expected_output['/admin/'] = (
+ b'Admin index\n'
+ b'<a href="/myapp/page/I%20l%C3%B8v%C3%AB%20Unicode/">Unicode test</a>\n'
+ b'<a href="/myapp/page/octothorp/?query_foo=bar#introduction">'
+ b'URL parsing test</a>')
def do_extra_config(self, app, freezer):
app.config['FREEZER_BASE_URL'] = 'http://example/myapp/'
@@ -399,11 +375,11 @@ def do_extra_config(self, app, freezer):
expected_output = TestFreezer.expected_output.copy()
expected_output['/admin/'] = (
- 'Admin index\n'
- '<a href="../page/I%20l%C3%B8v%C3%AB%20Unicode/index.html">'
- 'Unicode test</a>\n'
- '<a href="../page/octothorp/index.html?query_foo=bar#introduction">'
- 'URL parsing test</a>')
+ b'Admin index\n'
+ b'<a href="../page/I%20l%C3%B8v%C3%AB%20Unicode/index.html">'
+ b'Unicode test</a>\n'
+ b'<a href="../page/octothorp/index.html?query_foo=bar#introduction">'
+ b'URL parsing test</a>')
# with_no_argument_rules=False and with_static_files=False are
View
1  setup.py
@@ -13,7 +13,6 @@
<http://github.com/SimonSapin/Frozen-Flask/zipball/master#egg=Frozen-Flask-dev>`_
"""
-from __future__ import with_statement
import re
import os.path
from setuptools import setup, find_packages
View
2  tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py25, py26, py27, pypy
+envlist = py26, py27, py33, pypy
[testenv]
commands=python -m flask_frozen.tests
changedir=docs
Please sign in to comment.
Something went wrong with that request. Please try again.