|
25 | 25 | from django.http import Http404
|
26 | 26 | from django.urls import re_path
|
27 | 27 | from django.views import static
|
| 28 | +from django.contrib.staticfiles.finders import BaseFinder |
| 29 | +from django.utils._os import safe_join |
28 | 30 |
|
29 | 31 | # Bokeh imports
|
30 | 32 | from bokeh.embed.bundle import extension_dirs
|
|
33 | 35 | # General API
|
34 | 36 | # -----------------------------------------------------------------------------
|
35 | 37 |
|
| 38 | +class BokehExtensionFinder(BaseFinder): |
| 39 | + """ |
| 40 | + A custom staticfiles finder class to find bokeh resources. |
| 41 | +
|
| 42 | + In Django settings: |
| 43 | + When using `django.contrib.staticfiles' in `INSTALLED_APPS` then add |
| 44 | + `bokeh_django.static.BokehExtensionFinder` to `STATICFILES_FINDERS` |
| 45 | + """ |
| 46 | + _root = extension_dirs |
| 47 | + _prefix = 'extensions/' |
| 48 | + |
| 49 | + def find(self, path, all=False): |
| 50 | + """ |
| 51 | + Given a relative file path, find an absolute file path. |
| 52 | +
|
| 53 | + If the ``all`` parameter is False (default) return only the first found |
| 54 | + file path; if True, return a list of all found files paths. |
| 55 | + """ |
| 56 | + matches = [] |
| 57 | + location = self.find_location(path, self._prefix) |
| 58 | + if location: |
| 59 | + if not all: |
| 60 | + return location |
| 61 | + else: |
| 62 | + matches.append(location) |
| 63 | + |
| 64 | + return matches |
| 65 | + |
| 66 | + @classmethod |
| 67 | + def find_location(cls, path, prefix=None, as_components=False): |
| 68 | + """ |
| 69 | + Find the absolute path to a resouces given a relative path. |
| 70 | +
|
| 71 | + Args: |
| 72 | + path (str): relative path to resource |
| 73 | + prefix (str): if passed then verifies that path starts with `prefix` else returns `None` |
| 74 | + as_components (bool): If `True` return tuple of (artifacts_dir, artifact_path) rather than absolute path. |
| 75 | + Used when needing seperate components for `static.serve` function to manually serve resources. |
| 76 | + """ |
| 77 | + prefix = prefix or '' |
| 78 | + if not prefix or path.startswith(prefix): |
| 79 | + path = path[len(prefix):] |
| 80 | + try: |
| 81 | + name, artifact_path = path.split(os.sep, 1) |
| 82 | + except ValueError: |
| 83 | + pass |
| 84 | + else: |
| 85 | + artifacts_dir = cls._root.get(name, None) |
| 86 | + if artifacts_dir is not None: |
| 87 | + path = safe_join(artifacts_dir, artifact_path) |
| 88 | + if os.path.exists(path): |
| 89 | + if as_components: |
| 90 | + return artifacts_dir, artifact_path |
| 91 | + return path |
36 | 92 |
|
37 |
| -def serve_extensions(request, path): |
38 |
| - root = extension_dirs |
39 |
| - |
40 |
| - try: |
41 |
| - name, artifact_path = path.split(os.sep, 1) |
42 |
| - except ValueError: |
43 |
| - raise Http404 |
44 | 93 |
|
45 |
| - artifacts_dir = root.get(name, None) |
46 |
| - if artifacts_dir is not None: |
| 94 | +def serve_extensions(request, path): |
| 95 | + components = BokehExtensionFinder.find_location(path, as_components=True) |
| 96 | + if components is not None: |
| 97 | + artifacts_dir, artifact_path = components |
47 | 98 | return static.serve(request, artifact_path, document_root=artifacts_dir)
|
48 | 99 | else:
|
49 | 100 | raise Http404
|
|
0 commit comments