From d9a76e61e75f77fbacf6ee5525f64fe2ac37184f Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 27 Jun 2009 03:35:00 +0000 Subject: - Use the ``pkg_resources`` API to locate template filenames instead of dead-reckoning using the ``os.path`` module. --- CHANGES.txt | 9 ++++ repoze/bfg/path.py | 41 +++++++++-------- repoze/bfg/tests/test_path.py | 105 ++++++++++++++++++++++++++++++++---------- 3 files changed, 112 insertions(+), 43 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index e905e4cfd..94a17563d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,12 @@ +Next release +============ + +Features +-------- + +- Use the ``pkg_resources`` API to locate template filenames instead + of dead-reckoning using the ``os.path`` module. + 1.0a4 (2009-06-25) ================== diff --git a/repoze/bfg/path.py b/repoze/bfg/path.py index 6fee43791..d8e90f0ff 100644 --- a/repoze/bfg/path.py +++ b/repoze/bfg/path.py @@ -1,27 +1,32 @@ import os import sys +import pkg_resources -def caller_path(path, level=2, package_globals=None): # package_globals==testing +def caller_path(path, level=2): if not os.path.isabs(path): + module = caller_module(level+1) + prefix = package_path(module) + path = os.path.join(prefix, path) + return path - if package_globals is None: - package_globals = sys._getframe(level).f_globals - - if '__bfg_abspath__' in package_globals: - return os.path.join(package_globals['__bfg_abspath__'], path) +def caller_module(level=2): + module_globals = sys._getframe(level).f_globals + module_name = module_globals['__name__'] + module = sys.modules[module_name] + return module - # computing the abspath is actually kinda expensive so we - # memoize the result - package_name = package_globals['__name__'] - package = sys.modules[package_name] - prefix = package_path(package) +def package_path(package): + # computing the abspath is actually kinda expensive so we memoize + # the result + prefix = getattr(package, '__bfg_abspath__', None) + if prefix is None: + prefix = pkg_resources.resource_filename(package.__name__, '') + # pkg_resources doesn't care whether we feed it a package + # name or a module name within the package, the result + # will be the same: a directory name to the package itself try: - package_globals['__bfg_abspath__'] = prefix + package.__bfg_abspath__ = prefix except: + # this is only an optimization, ignore any error pass - path = os.path.join(prefix, path) - return path - -def package_path(package): - return os.path.abspath(os.path.dirname(package.__file__)) - + return prefix diff --git a/repoze/bfg/tests/test_path.py b/repoze/bfg/tests/test_path.py index 42ab1f8fe..e8068e52d 100644 --- a/repoze/bfg/tests/test_path.py +++ b/repoze/bfg/tests/test_path.py @@ -1,51 +1,106 @@ import unittest class TestCallerPath(unittest.TestCase): - def _callFUT(self, path, level=2, package_globals=None): + def tearDown(self): + from repoze.bfg.tests import test_path + if hasattr(test_path, '__bfg_abspath__'): + del test_path.__bfg_abspath__ + + def _callFUT(self, path, level=2): from repoze.bfg.path import caller_path - return caller_path(path, level, package_globals) + return caller_path(path, level) def test_isabs(self): - self.assertEqual(self._callFUT('/a/b/c'), '/a/b/c') + result = self._callFUT('/a/b/c') + self.assertEqual(result, '/a/b/c') def test_pkgrelative(self): import os here = os.path.abspath(os.path.dirname(__file__)) - self.assertEqual(self._callFUT('a/b/c'), os.path.join(here, 'a/b/c')) + result = self._callFUT('a/b/c') + self.assertEqual(result, os.path.join(here, 'a/b/c')) def test_memoization_has_bfg_abspath(self): import os + from repoze.bfg.tests import test_path + test_path.__bfg_abspath__ = '/foo/bar' here = os.path.abspath(os.path.dirname(__file__)) - package_globals = {'__bfg_abspath__':'/foo/bar'} - self.assertEqual( - self._callFUT('a/b/c', - package_globals=package_globals), - os.path.join('/foo/bar', 'a/b/c')) + result = self._callFUT('a/b/c') + self.assertEqual(result, os.path.join('/foo/bar', 'a/b/c')) def test_memoization_success(self): import os here = os.path.abspath(os.path.dirname(__file__)) - package_globals = {'__name__':'repoze.bfg.tests.test_path'} - self.assertEqual( - self._callFUT('a/b/c', - package_globals=package_globals), - os.path.join(here, 'a/b/c')) - self.assertEqual(package_globals['__bfg_abspath__'], here) + from repoze.bfg.tests import test_path + result = self._callFUT('a/b/c') + self.assertEqual(result, os.path.join(here, 'a/b/c')) + self.assertEqual(test_path.__bfg_abspath__, here) + +class TestCallerModule(unittest.TestCase): + def _callFUT(self, level=2): + from repoze.bfg.path import caller_module + return caller_module(level) + + def test_it_level_1(self): + from repoze.bfg.tests import test_path + result = self._callFUT(1) + self.assertEqual(result, test_path) + + def test_it_level_2(self): + from repoze.bfg.tests import test_path + result = self._callFUT(2) + self.assertEqual(result, test_path) + + def test_it_level_3(self): + import unittest + result = self._callFUT(3) + self.assertEqual(result, unittest) + +class TestPackagePath(unittest.TestCase): + def _callFUT(self, package): + from repoze.bfg.path import package_path + return package_path(package) + + def test_it_package(self): + from repoze.bfg import tests + package = DummyPackageOrModule(tests) + result = self._callFUT(package) + self.assertEqual(result, package.package_path) + + def test_it_module(self): + from repoze.bfg.tests import test_path + module = DummyPackageOrModule(test_path) + result = self._callFUT(module) + self.assertEqual(result, module.package_path) + + def test_memoization_success(self): + from repoze.bfg.tests import test_path + module = DummyPackageOrModule(test_path) + result = self._callFUT(module) + self.assertEqual(module.__bfg_abspath__, module.package_path) def test_memoization_fail(self): + from repoze.bfg.tests import test_path + module = DummyPackageOrModule(test_path, raise_exc=TypeError) + result = self._callFUT(module) + self.failIf(hasattr(module, '__bfg_abspath__')) + self.assertEqual(result, module.package_path) + +class DummyPackageOrModule: + def __init__(self, real_package_or_module, raise_exc=None): + self.__dict__['raise_exc'] = raise_exc + self.__dict__['__name__'] = real_package_or_module.__name__ import os - here = os.path.abspath(os.path.dirname(__file__)) - class faildict(dict): - def __setitem__(self, *arg): - raise KeyError('name') - package_globals = faildict({'__name__':'repoze.bfg.tests.test_path'}) - self.assertEqual( - self._callFUT('a/b/c', - package_globals=package_globals), - os.path.join(here, 'a/b/c')) - self.failIf('__bfg_abspath__' in package_globals) + self.__dict__['package_path'] = os.path.dirname( + os.path.abspath(real_package_or_module.__file__)) + + def __setattr__(self, key, val): + if self.raise_exc is not None: + raise self.raise_exc + self.__dict__[key] = val + -- cgit v1.2.3