| 37 | |
| 38 | |
| 39 | class StaticFiles: |
| 40 | def __init__( |
| 41 | self, |
| 42 | *, |
| 43 | directory: PathLike | None = None, |
| 44 | packages: list[str | tuple[str, str]] | None = None, |
| 45 | html: bool = False, |
| 46 | check_dir: bool = True, |
| 47 | follow_symlink: bool = False, |
| 48 | ) -> None: |
| 49 | self.directory = directory |
| 50 | self.packages = packages |
| 51 | self.all_directories = self.get_directories(directory, packages) |
| 52 | self.html = html |
| 53 | self.config_checked = False |
| 54 | self.follow_symlink = follow_symlink |
| 55 | if check_dir and directory is not None and not os.path.isdir(directory): |
| 56 | raise RuntimeError(f"Directory '{directory}' does not exist") |
| 57 | |
| 58 | def get_directories( |
| 59 | self, |
| 60 | directory: PathLike | None = None, |
| 61 | packages: list[str | tuple[str, str]] | None = None, |
| 62 | ) -> list[PathLike]: |
| 63 | """ |
| 64 | Given `directory` and `packages` arguments, return a list of all the |
| 65 | directories that should be used for serving static files from. |
| 66 | """ |
| 67 | directories = [] |
| 68 | if directory is not None: |
| 69 | directories.append(directory) |
| 70 | |
| 71 | for package in packages or []: |
| 72 | if isinstance(package, tuple): |
| 73 | package, statics_dir = package |
| 74 | else: |
| 75 | statics_dir = "statics" |
| 76 | spec = importlib.util.find_spec(package) |
| 77 | assert spec is not None, f"Package {package!r} could not be found." |
| 78 | assert spec.origin is not None, f"Package {package!r} could not be found." |
| 79 | package_directory = os.path.normpath(os.path.join(spec.origin, "..", statics_dir)) |
| 80 | assert os.path.isdir(package_directory), ( |
| 81 | f"Directory '{statics_dir!r}' in package {package!r} could not be found." |
| 82 | ) |
| 83 | directories.append(package_directory) |
| 84 | |
| 85 | return directories |
| 86 | |
| 87 | async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: |
| 88 | """ |
| 89 | The ASGI entry point. |
| 90 | """ |
| 91 | assert scope["type"] == "http" |
| 92 | |
| 93 | if not self.config_checked: |
| 94 | await self.check_config() |
| 95 | self.config_checked = True |
| 96 |
no outgoing calls