Allow Pathlib Path objects to be passed to app.static()
helper (#2008)
* Allow Pathlib Path objects to be passed to the app.static file endpoint register helper. * fixed import sort * Raise error if static file path is not an accepted object type Added more tests to improve coverage on the new type checks.
This commit is contained in:
parent
0c252e7904
commit
6c03dd87b1
|
@ -1,8 +1,10 @@
|
||||||
from functools import partial, wraps
|
from functools import partial, wraps
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from os import path
|
from os import path
|
||||||
|
from pathlib import PurePath
|
||||||
from re import sub
|
from re import sub
|
||||||
from time import gmtime, strftime
|
from time import gmtime, strftime
|
||||||
|
from typing import Union
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from sanic.compat import stat_async
|
from sanic.compat import stat_async
|
||||||
|
@ -110,13 +112,13 @@ async def _static_request_handler(
|
||||||
|
|
||||||
def register(
|
def register(
|
||||||
app,
|
app,
|
||||||
uri,
|
uri: str,
|
||||||
file_or_directory,
|
file_or_directory: Union[str, bytes, PurePath],
|
||||||
pattern,
|
pattern,
|
||||||
use_modified_since,
|
use_modified_since,
|
||||||
use_content_range,
|
use_content_range,
|
||||||
stream_large_files,
|
stream_large_files,
|
||||||
name="static",
|
name: str = "static",
|
||||||
host=None,
|
host=None,
|
||||||
strict_slashes=None,
|
strict_slashes=None,
|
||||||
content_type=None,
|
content_type=None,
|
||||||
|
@ -130,7 +132,9 @@ def register(
|
||||||
|
|
||||||
:param app: Sanic
|
:param app: Sanic
|
||||||
:param file_or_directory: File or directory path to serve from
|
:param file_or_directory: File or directory path to serve from
|
||||||
|
:type file_or_directory: Union[str,bytes,Path]
|
||||||
:param uri: URL to serve from
|
:param uri: URL to serve from
|
||||||
|
:type uri: str
|
||||||
:param pattern: regular expression used to match files in the URL
|
:param pattern: regular expression used to match files in the URL
|
||||||
:param use_modified_since: If true, send file modified time, and return
|
:param use_modified_since: If true, send file modified time, and return
|
||||||
not modified if the browser's matches the
|
not modified if the browser's matches the
|
||||||
|
@ -142,10 +146,19 @@ def register(
|
||||||
If this is an integer, this represents the
|
If this is an integer, this represents the
|
||||||
threshold size to switch to file_stream()
|
threshold size to switch to file_stream()
|
||||||
:param name: user defined name used for url_for
|
:param name: user defined name used for url_for
|
||||||
|
:type name: str
|
||||||
:param content_type: user defined content type for header
|
:param content_type: user defined content type for header
|
||||||
:return: registered static routes
|
:return: registered static routes
|
||||||
:rtype: List[sanic.router.Route]
|
:rtype: List[sanic.router.Route]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if isinstance(file_or_directory, bytes):
|
||||||
|
file_or_directory = file_or_directory.decode("utf-8")
|
||||||
|
elif isinstance(file_or_directory, PurePath):
|
||||||
|
file_or_directory = str(file_or_directory)
|
||||||
|
elif not isinstance(file_or_directory, str):
|
||||||
|
raise ValueError("Invalid file path string.")
|
||||||
|
|
||||||
# If we're not trying to match a file directly,
|
# If we're not trying to match a file directly,
|
||||||
# serve from the folder
|
# serve from the folder
|
||||||
if not path.isfile(file_or_directory):
|
if not path.isfile(file_or_directory):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from time import gmtime, strftime
|
from time import gmtime, strftime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -76,6 +76,41 @@ def test_static_file(app, static_file_directory, file_name):
|
||||||
assert response.body == get_file_content(static_file_directory, file_name)
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"file_name",
|
||||||
|
["test.file", "decode me.txt", "python.png", "symlink", "hard_link"],
|
||||||
|
)
|
||||||
|
def test_static_file_pathlib(app, static_file_directory, file_name):
|
||||||
|
file_path = Path(get_file_path(static_file_directory, file_name))
|
||||||
|
app.static("/testing.file", file_path)
|
||||||
|
request, response = app.test_client.get("/testing.file")
|
||||||
|
assert response.status == 200
|
||||||
|
assert response.body == get_file_content(static_file_directory, file_name)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"file_name",
|
||||||
|
[b"test.file", b"decode me.txt", b"python.png"],
|
||||||
|
)
|
||||||
|
def test_static_file_bytes(app, static_file_directory, file_name):
|
||||||
|
bsep = os.path.sep.encode('utf-8')
|
||||||
|
file_path = static_file_directory.encode('utf-8') + bsep + file_name
|
||||||
|
app.static("/testing.file", file_path)
|
||||||
|
request, response = app.test_client.get("/testing.file")
|
||||||
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"file_name",
|
||||||
|
[dict(), list(), object()],
|
||||||
|
)
|
||||||
|
def test_static_file_invalid_path(app, static_file_directory, file_name):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
app.static("/testing.file", file_name)
|
||||||
|
request, response = app.test_client.get("/testing.file")
|
||||||
|
assert response.status == 404
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("file_name", ["test.html"])
|
@pytest.mark.parametrize("file_name", ["test.html"])
|
||||||
def test_static_file_content_type(app, static_file_directory, file_name):
|
def test_static_file_content_type(app, static_file_directory, file_name):
|
||||||
app.static(
|
app.static(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user