Skip to content

Commit

Permalink
Use os.PathLike in StaticFiles for directory
Browse files Browse the repository at this point in the history
This allows using `pathlib.Path` in addition to `str` for configuring
the base directory of the static files in line with how python3.6+
handles filesystem operations.

Fixes encode#1004
  • Loading branch information
kevinastone committed Aug 5, 2020
1 parent 518da5e commit 1c2bc25
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 8 deletions.
2 changes: 1 addition & 1 deletion starlette/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ class FileResponse(Response):

def __init__(
self,
path: str,
path: typing.Union[str, "os.PathLike[str]"],
status_code: int = 200,
headers: dict = None,
media_type: str = None,
Expand Down
18 changes: 11 additions & 7 deletions starlette/staticfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
)
from starlette.types import Receive, Scope, Send

PathLike = typing.Union[str, "os.PathLike[str]"]


class NotModifiedResponse(Response):
NOT_MODIFIED_HEADERS = (
Expand All @@ -41,7 +43,7 @@ class StaticFiles:
def __init__(
self,
*,
directory: str = None,
directory: PathLike = None,
packages: typing.List[str] = None,
html: bool = False,
check_dir: bool = True,
Expand All @@ -55,8 +57,8 @@ def __init__(
raise RuntimeError(f"Directory '{directory}' does not exist")

def get_directories(
self, directory: str = None, packages: typing.List[str] = None
) -> typing.List[str]:
self, directory: PathLike = None, packages: typing.List[str] = None
) -> typing.List[PathLike]:
"""
Given `directory` and `packages` arguments, return a list of all the
directories that should be used for serving static files from.
Expand All @@ -71,11 +73,13 @@ def get_directories(
assert (
spec.origin is not None
), f"Directory 'statics' in package {package!r} could not be found."
directory = os.path.normpath(os.path.join(spec.origin, "..", "statics"))
package_directory = os.path.normpath(
os.path.join(spec.origin, "..", "statics")
)
assert os.path.isdir(
directory
package_directory
), f"Directory 'statics' in package {package!r} could not be found."
directories.append(directory)
directories.append(package_directory)

return directories

Expand Down Expand Up @@ -154,7 +158,7 @@ async def lookup_path(

def file_response(
self,
full_path: str,
full_path: PathLike,
stat_result: os.stat_result,
scope: Scope,
status_code: int = 200,
Expand Down
14 changes: 14 additions & 0 deletions tests/test_staticfiles.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import os
import pathlib
import time

import pytest
Expand All @@ -23,6 +24,19 @@ def test_staticfiles(tmpdir):
assert response.text == "<file content>"


def test_staticfiles_with_pathlib(tmpdir):
base_dir = pathlib.Path(tmpdir)
path = base_dir / "example.txt"
with open(path, "w") as file:
file.write("<file content>")

app = StaticFiles(directory=base_dir)
client = TestClient(app)
response = client.get("/example.txt")
assert response.status_code == 200
assert response.text == "<file content>"


def test_staticfiles_head_with_middleware(tmpdir):
"""
see https://github.com/encode/starlette/pull/935
Expand Down

0 comments on commit 1c2bc25

Please sign in to comment.