From 175d43b2f9c7825b0df4c1049ab571cb1877a807 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 10 Aug 2011 17:46:20 +0200 Subject: [PATCH] Instance paths are now moved into virtualenv/share/appname-instance if installed --- flask/app.py | 41 ++++++++++++++++++++++++++----- flask/helpers.py | 4 ++-- tests/flask_tests.py | 57 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 93 insertions(+), 9 deletions(-) diff --git a/flask/app.py b/flask/app.py index 636da286..b8f07fcd 100644 --- a/flask/app.py +++ b/flask/app.py @@ -447,6 +447,23 @@ class Flask(_PackageBoundObject): error_handlers = property(_get_error_handlers, _set_error_handlers) del _get_error_handlers, _set_error_handlers + @locked_cached_property + def name(self): + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overriden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == '__main__': + fn = getattr(sys.modules['__main__'], '__file__', None) + if fn is None: + return 'unknown' + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + @property def propagate_exceptions(self): """Returns the value of the `PROPAGATE_EXCEPTIONS` configuration @@ -545,14 +562,26 @@ class Flask(_PackageBoundObject): .. versionadded:: 0.8 """ root_mod = sys.modules[self.import_name.split('.')[0]] - instance_path = None + # we're not using root_mod.__file__ here since the module could be + # virtual. We're trusting the _PackageBoundObject to have calculated + # the proper name. + package_path = self.root_path if hasattr(root_mod, '__path__'): - package_dir = os.path.dirname(root_mod.__file__) - instance_path = os.path.join(package_dir, os.path.pardir) + package_path = os.path.dirname(package_path) + site_parent, site_folder = os.path.split(package_path) + + py_prefix = os.path.abspath(sys.prefix) + if package_path.startswith(py_prefix): + base_dir = py_prefix + elif site_folder == 'site-packages': + parent, folder = os.path.split(site_parent) + if folder.lower() == 'lib': + base_dir = parent + else: + base_dir = site_parent else: - instance_path = os.path.dirname(root_mod.__file__) - basedir = os.path.normpath(os.path.abspath(instance_path)) - return os.path.join(basedir, 'instance') + return os.path.join(package_path, 'instance') + return os.path.join(base_dir, 'share', self.name + '-instance') def open_instance_resource(self, resource, mode='rb'): """Opens a resource from the application's instance folder diff --git a/flask/helpers.py b/flask/helpers.py index 338f5a5a..89fc82cb 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -466,7 +466,7 @@ def send_from_directory(directory, filename, **options): return send_file(filename, conditional=True, **options) -def _get_package_path(name): +def get_package_path(name): """Returns the path to a package or cwd if that cannot be found.""" try: return os.path.abspath(os.path.dirname(sys.modules[name].__file__)) @@ -512,7 +512,7 @@ class _PackageBoundObject(object): self.template_folder = template_folder #: Where is the app root located? - self.root_path = _get_package_path(self.import_name) + self.root_path = get_package_path(self.import_name) self._static_folder = None self._static_url_path = None diff --git a/tests/flask_tests.py b/tests/flask_tests.py index 6e9f4555..63ecad97 100644 --- a/tests/flask_tests.py +++ b/tests/flask_tests.py @@ -1005,7 +1005,10 @@ class BasicFunctionalityTestCase(unittest.TestCase): rv = c.post('/foo', data={}, follow_redirects=True) self.assertEqual(rv.data, 'success') - def test_basic_instance_paths(self): + +class InstanceTestCase(unittest.TestCase): + + def test_uninstalled_module_paths(self): here = os.path.abspath(os.path.dirname(__file__)) app = flask.Flask(__name__) self.assertEqual(app.instance_path, os.path.join(here, 'instance')) @@ -1020,9 +1023,60 @@ class BasicFunctionalityTestCase(unittest.TestCase): else: self.fail('Expected value error') + def test_uninstalled_package_paths(self): from blueprintapp import app + here = os.path.abspath(os.path.dirname(__file__)) self.assertEqual(app.instance_path, os.path.join(here, 'instance')) + def test_installed_module_paths(self): + import types + expected_prefix = os.path.abspath('foo') + mod = types.ModuleType('myapp') + mod.__file__ = os.path.join(expected_prefix, 'lib', + 'site-packages', 'myapp.py') + sys.modules['myapp'] = mod + try: + mod.app = flask.Flask(mod.__name__) + self.assertEqual(mod.app.instance_path, + os.path.join(expected_prefix, 'share', + 'myapp-instance')) + finally: + sys.modules['myapp'] = None + + def test_installed_package_paths(self): + import types + expected_prefix = os.path.abspath('foo') + package_path = os.path.join(expected_prefix, 'lib', + 'site-packages', 'myapp') + mod = types.ModuleType('myapp') + mod.__path__ = [package_path] + mod.__file__ = os.path.join(package_path, '__init__.py') + sys.modules['myapp'] = mod + try: + mod.app = flask.Flask(mod.__name__) + self.assertEqual(mod.app.instance_path, + os.path.join(expected_prefix, 'share', + 'myapp-instance')) + finally: + sys.modules['myapp'] = None + + def test_prefix_installed_paths(self): + import types + expected_prefix = os.path.abspath(sys.prefix) + package_path = os.path.join(expected_prefix, 'lib', + 'site-packages', 'myapp') + mod = types.ModuleType('myapp') + mod.__path__ = [package_path] + mod.__file__ = os.path.join(package_path, '__init__.py') + sys.modules['myapp'] = mod + try: + mod.app = flask.Flask(mod.__name__) + self.assertEqual(mod.app.instance_path, + os.path.join(expected_prefix, 'share', + 'myapp-instance')) + finally: + sys.modules['myapp'] = None + class JSONTestCase(unittest.TestCase): @@ -2114,6 +2168,7 @@ def suite(): suite.addTest(unittest.makeSuite(SubdomainTestCase)) suite.addTest(unittest.makeSuite(ViewTestCase)) suite.addTest(unittest.makeSuite(DeprecationsTestCase)) + suite.addTest(unittest.makeSuite(InstanceTestCase)) if flask.json_available: suite.addTest(unittest.makeSuite(JSONTestCase)) if flask.signals_available: