Provides shared logic for writing an app to local disk
| 135 | ############################################################################### |
| 136 | # HTML Exporting Processors |
| 137 | class BaseExportHTML(BaseProcessor, ABC): |
| 138 | """Provides shared logic for writing an app to local disk""" |
| 139 | |
| 140 | # Type is `ir.abc.Traversable` which extends `Path`, |
| 141 | # but the former isn't compatible with `shutil` |
| 142 | template_dir: Path = t.cast(Path, ir.files("datapane.resources.html_templates")) |
| 143 | template: SimpleTemplate |
| 144 | template_name: str |
| 145 | |
| 146 | def __init_subclass__(cls, **kwargs): |
| 147 | super().__init_subclass__(**kwargs) |
| 148 | # TODO (JB) - why doesn't altering TEMPLATE_PATH work as described in docs? Need to pass dir to `lookup` kwarg instead |
| 149 | cls.template = SimpleTemplate(name=cls.template_name, lookup=[str(cls.template_dir)]) |
| 150 | |
| 151 | def get_cdn(self) -> str: |
| 152 | from datapane import __is_dev_build__, __version__ |
| 153 | |
| 154 | if cdn_base := os.getenv("DATAPANE_CDN_BASE"): |
| 155 | return cdn_base |
| 156 | elif __is_dev_build__: |
| 157 | return "https://datapane-cdn.com/dev" |
| 158 | else: |
| 159 | return f"https://datapane-cdn.com/v{__version__}" |
| 160 | |
| 161 | def escape_json_htmlsafe(self, obj: t.Any) -> str: |
| 162 | """Escape JSON object for embedding in bottle templates.""" |
| 163 | |
| 164 | # Taken from Jinja2's |tojson pipe function |
| 165 | # (https://github.com/pallets/jinja/blob/b7cb6ee6675b12a027c5e7518f832b2926dfe293/src/jinja2/utils.py#L628) |
| 166 | # Use of markupsafe is removed, as we use bottle's SimpleTemplate. |
| 167 | return ( |
| 168 | json.dumps(obj) |
| 169 | .replace("<", "\\u003c") |
| 170 | .replace(">", "\\u003e") |
| 171 | .replace("&", "\\u0026") |
| 172 | .replace("'", "\\u0027") |
| 173 | ) |
| 174 | |
| 175 | def _write_html_template( |
| 176 | self, |
| 177 | name: str, |
| 178 | formatting: t.Optional[Formatting] = None, |
| 179 | app_runner: bool = False, |
| 180 | ) -> t.Tuple[str, str]: |
| 181 | """Internal method to write the ViewXML and assets into a HTML container and associated files""" |
| 182 | name = name or "app" |
| 183 | formatting = formatting or Formatting() |
| 184 | |
| 185 | report_id: str = uuid4().hex |
| 186 | |
| 187 | # TODO - split this out? |
| 188 | vs = self.s |
| 189 | if vs: |
| 190 | assets = vs.store.as_dict() or {} |
| 191 | view_xml = vs.view_xml |
| 192 | else: |
| 193 | assets = {} |
| 194 | view_xml = "" |