Browse Source

Added tests for the import hook and fixed a problem with it.

pull/325/head
Armin Ronacher 13 years ago
parent
commit
c72ca16234
  1. 40
      flask/ext/__init__.py
  2. 61
      flask/testsuite/ext.py
  3. 1
      flask/testsuite/test_apps/flask_newext_package/__init__.py
  4. 2
      flask/testsuite/test_apps/flask_newext_package/submodule.py
  5. 1
      flask/testsuite/test_apps/flask_newext_simple.py

40
flask/ext/__init__.py

@ -8,7 +8,7 @@
force all extensions to upgrade at the same time. force all extensions to upgrade at the same time.
When a user does ``from flask.ext.foo import bar`` it will attempt to When a user does ``from flask.ext.foo import bar`` it will attempt to
imprt ``from flask_foo import bar`` first and when that fails it will import ``from flask_foo import bar`` first and when that fails it will
try to import ``from flaskext.foo import bar``. try to import ``from flaskext.foo import bar``.
We're switching from namespace packages because it was just too painful for We're switching from namespace packages because it was just too painful for
@ -17,38 +17,46 @@
:copyright: (c) 2011 by Armin Ronacher. :copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import sys
class _ExtensionImporter(object): class _ExtensionImporter(object):
"""This importer redirects imports from this submodule to other """This importer redirects imports from this submodule to other locations.
locations. This makes it possible to transition from the old This makes it possible to transition from the old flaskext.name to the
flaskext.name to the newer flask_name without people having a newer flask_name without people having a hard time.
hard time.
""" """
_module_choices = ['flask_%s', 'flaskext.%s'] _module_choices = ['flask_%s', 'flaskext.%s']
_modules = sys.modules
def __init__(self):
from sys import meta_path
self.prefix = __name__ + '.'
self.prefix_cutoff = __name__.count('.') + 1
def _name(x):
cls = type(x)
return cls.__module__ + '.' + cls.__name__
this = _name(self)
meta_path[:] = [x for x in meta_path if _name(x) != this] + [self]
def find_module(self, fullname, path=None): def find_module(self, fullname, path=None):
if fullname.rsplit('.', 1)[0] == __name__: if fullname.startswith(self.prefix):
return self return self
def load_module(self, fullname): def load_module(self, fullname):
if fullname in self._modules: from sys import modules
return self._modules[fullname] if fullname in modules:
packname, modname = fullname.rsplit('.', 1) return modules[fullname]
modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff]
for path in self._module_choices: for path in self._module_choices:
realname = path % modname realname = path % modname
try: try:
__import__(realname) __import__(realname)
except ImportError: except ImportError:
continue continue
module = self._modules[fullname] = self._modules[realname] module = modules[fullname] = modules[realname]
setattr(self._modules[__name__], modname, module) setattr(modules[__name__], modname, module)
module.__loader__ = self
return module return module
raise ImportError(fullname) raise ImportError(fullname)
sys.meta_path.append(_ExtensionImporter()) _ExtensionImporter()
del sys, _ExtensionImporter del _ExtensionImporter

61
flask/testsuite/ext.py

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.ext
~~~~~~~~~~~~~~~~~~~
Tests the extension import thing.
:copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import sys
import unittest
from flask.testsuite import FlaskTestCase
class ExtImportHookTestCase(FlaskTestCase):
def setup(self):
for entry, value in sys.modules.items():
if entry.startswith('flask.ext.') and value is not None:
sys.modules.pop(entry, None)
from flask import ext
reload(ext)
# reloading must not add more hooks
import_hooks = 0
for item in sys.meta_path:
cls = type(item)
if cls.__module__ == 'flask.ext' and \
cls.__name__ == '_ExtensionImporter':
import_hooks += 1
self.assert_equal(import_hooks, 1)
def test_flaskext_simple_import_normal(self):
from flask.ext.newext_simple import ext_id
self.assert_equal(ext_id, 'newext_simple')
def test_flaskext_simple_import_module(self):
from flask.ext import newext_simple
self.assert_equal(newext_simple.ext_id, 'newext_simple')
self.assert_equal(newext_simple.__name__, 'flask_newext_simple')
def test_flaskext_package_import_normal(self):
from flask.ext.newext_package import ext_id
self.assert_equal(ext_id, 'newext_package')
def test_flaskext_package_import_module(self):
from flask.ext import newext_package
self.assert_equal(newext_package.ext_id, 'newext_package')
self.assert_equal(newext_package.__name__, 'flask_newext_package')
def test_flaskext_package_import_submodule(self):
from flask.ext.newext_package import submodule
self.assert_equal(submodule.__name__, 'flask_newext_package.submodule')
self.assert_equal(submodule.test_function(), 42)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(ExtImportHookTestCase))
return suite

1
flask/testsuite/test_apps/flask_newext_package/__init__.py

@ -0,0 +1 @@
ext_id = 'newext_package'

2
flask/testsuite/test_apps/flask_newext_package/submodule.py

@ -0,0 +1,2 @@
def test_function():
return 42

1
flask/testsuite/test_apps/flask_newext_simple.py

@ -0,0 +1 @@
ext_id = 'newext_simple'
Loading…
Cancel
Save