diff --git a/bottle.py b/bottle.py index 7ac53782d..5032dd3f9 100755 --- a/bottle.py +++ b/bottle.py @@ -14,6 +14,7 @@ """ import sys +from pathlib import Path __author__ = 'Marcel Hellkamp' __version__ = '0.14-dev' @@ -2306,10 +2307,16 @@ def load_config(self, filename, **options): other sections. :param filename: The path of a config file, or a list of paths. + Can be a string or a :class:`pathlib.Path` object. :param options: All keyword parameters are passed to the underlying :class:`python:configparser.ConfigParser` constructor call. """ + if isinstance(filename, Path): + filename = str(filename) + elif isinstance(filename, (list, tuple)): + filename = [str(f) if isinstance(f, Path) else f for f in filename] + options.setdefault('allow_no_value', True) options.setdefault('interpolation', configparser.ExtendedInterpolation()) conf = configparser.ConfigParser(**options) @@ -2746,8 +2753,9 @@ def static_file(filename, root, that can be sent back to the client. :param filename: Name or path of the file to send, relative to ``root``. + Can be a string or a :class:`pathlib.Path` object. :param root: Root path for file lookups. Should be an absolute directory - path. + path. Can be a string or a :class:`pathlib.Path` object. :param mimetype: Provide the content-type header (default: guess from file extension) :param download: If True, ask the browser to open a `Save as...` dialog @@ -2773,6 +2781,11 @@ def static_file(filename, root, check or continue partial downloads) are also handled automatically. """ + if isinstance(root, Path): + root = str(root) + if isinstance(filename, Path): + filename = str(filename) + root = os.path.join(os.path.abspath(root), '') filename = os.path.abspath(os.path.join(root, filename.strip('/\\'))) headers = headers.copy() if headers else {} @@ -3976,7 +3989,10 @@ def __init__(self, self.name = name self.source = source.read() if hasattr(source, 'read') else source self.filename = source.filename if hasattr(source, 'filename') else None - self.lookup = [os.path.abspath(x) for x in lookup] if lookup else [] + if lookup: + self.lookup = [os.path.abspath(str(x) if isinstance(x, Path) else x) for x in lookup] + else: + self.lookup = [] self.encoding = encoding self.settings = self.settings.copy() # Copy from class variable self.settings.update(settings) # Apply @@ -3999,6 +4015,8 @@ def search(cls, name, lookup=None): raise depr(0, 12, "Use of absolute path for template name.", "Refer to templates with names or paths relative to the lookup path.") + lookup = [str(path) if isinstance(path, Path) else path for path in lookup] + for spath in lookup: spath = os.path.abspath(spath) + os.sep fname = os.path.abspath(os.path.join(spath, name)) diff --git a/test/test_config.py b/test/test_config.py index d55227397..a3f76e8dc 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -1,6 +1,7 @@ import os import tempfile import unittest +from pathlib import Path from bottle import ConfigDict @@ -198,3 +199,8 @@ def test_load_config(self): 'namespace.section.default': 'otherDefault', 'namespace.section.sub.namespace.key': 'test2', 'port': '8080'}, c) + + # Test with pathlib.Path object + c2 = ConfigDict() + c2.load_config(Path(self.config_file.name)) + self.assertDictEqual(c, c2) diff --git a/test/test_sendfile.py b/test/test_sendfile.py index 3a332c640..2b044134f 100755 --- a/test/test_sendfile.py +++ b/test/test_sendfile.py @@ -1,5 +1,6 @@ import sys import unittest +from pathlib import Path from bottle import static_file, request, response, parse_date, parse_range_header, Bottle, tob import bottle import wsgiref.util @@ -57,6 +58,9 @@ def test_valid(self): out = static_file(basename, root=root) self.assertEqual(open(__file__,'rb').read(), out.body.read()) + out_path = static_file(Path(basename), root=Path(root)) + self.assertEqual(open(__file__,'rb').read(), out_path.body.read()) + def test_invalid(self): """ SendFile: Invalid requests""" self.assertEqual(404, static_file('not/a/file', root=root).status_code) diff --git a/test/test_stpl.py b/test/test_stpl.py index 73f37d320..3fd0955e8 100755 --- a/test/test_stpl.py +++ b/test/test_stpl.py @@ -4,6 +4,7 @@ from bottle import SimpleTemplate, TemplateError, view, template, touni, tob, html_quote import re, os import traceback +from pathlib import Path from .tools import chdir @@ -24,6 +25,9 @@ def test_file(self): with chdir(__file__): t = SimpleTemplate(name='./views/stpl_simple.tpl', lookup=['.']) self.assertRenders(t, 'start var end\n', var='var') + with chdir(__file__): + t = SimpleTemplate(name='./views/stpl_simple.tpl', lookup=[Path('.')]) + self.assertRenders(t, 'start var end\n', var='var') def test_name(self): with chdir(__file__):