Esempio n. 1
0
 def test_path_does_not_exist(self, tmp_path: Path) -> None:
     with pytest.raises(LinkToNonExistentFileError):
         postprocess_html(
             t("a", "foo", href="bar.txt"),
             False,
             [
                 partial(
                     embed_local_links_as_data_urls,
                     source=tmp_path / "foo.md",
                     root=tmp_path,
                 ),
             ],
         )
Esempio n. 2
0
 def test_path_outside_root(self, tmp_path: Path) -> None:
     with pytest.raises(LinkToExternalFileError):
         postprocess_html(
             t("a", "foo", href="../bar.txt"),
             False,
             [
                 partial(
                     embed_local_links_as_data_urls,
                     source=tmp_path / "foo.md",
                     root=tmp_path,
                 ),
             ],
         )
Esempio n. 3
0
    def render(
        self,
        source_to_page_paths: Mapping[Path, Tuple[str, bool]],
        filename_to_asset_paths: MutableMapping[Path, str],
    ) -> str:
        body = postprocess_html(
            self.recipe_html,
            complete_document=False,
            stages=[
                self.get_resolve_local_links_stage(
                    source=self.recipe_source,
                    source_to_page_paths=source_to_page_paths,
                    filename_to_asset_paths=filename_to_asset_paths,
                ),
                partial(
                    add_recipe_scaling_links,
                    from_path=self.path,
                    scaled_paths={
                        num_servings: recipe_page.path
                        for num_servings, recipe_page in self.other_scalings.items()
                    },
                    native_servings=self.native_servings,
                ),
            ],
        )

        return recipe_template.render(
            body=body,
            **self.get_template_variables(),
        )
Esempio n. 4
0
    def render(
        self,
        source_to_page_paths: Mapping[Path, Tuple[str, bool]],
        filename_to_asset_paths: MutableMapping[Path, str],
    ) -> str:
        description: str = ""
        if self.description_html is not None and self.description_source is not None:
            description = postprocess_html(
                self.description_html,
                complete_document=False,
                stages=[
                    self.get_resolve_local_links_stage(
                        source=self.description_source,
                        source_to_page_paths=source_to_page_paths,
                        filename_to_asset_paths=filename_to_asset_paths,
                    )
                ],
            )

        categories = [
            (categories_page.title, href.relative(self.path, categories_page.path))
            for categories_page in self.subcategories
        ]

        recipes = [
            (recipes_page.title, href.relative(self.path, recipes_page.path))
            for recipes_page in self.recipes
        ]

        return categories_template.render(
            description=description,
            categories=categories,
            recipes=recipes,
            **self.get_template_variables(),
        )
Esempio n. 5
0
    def render(
        self,
        source_to_page_paths: Mapping[Path, Tuple[str, bool]],
        filename_to_asset_paths: MutableMapping[Path, str],
    ) -> str:
        welcome_message: str = ""
        if (
            self.welcome_message_html is not None
            and self.welcome_message_source is not None
        ):
            welcome_message = postprocess_html(
                self.welcome_message_html,
                complete_document=False,
                stages=[
                    self.get_resolve_local_links_stage(
                        source=self.welcome_message_source,
                        source_to_page_paths=source_to_page_paths,
                        filename_to_asset_paths=filename_to_asset_paths,
                    )
                ],
            )

        serving_page_hrefs = [
            (num_servings, href.relative(self.path, categories_page.path))
            for num_servings, categories_page in sorted(self.scaled_categories.items())
        ]

        categories_page_href = href.relative(self.path, self.unscaled_categories.path)

        return homepage_template.render(
            welcome_message=welcome_message,
            serving_page_hrefs=serving_page_hrefs,
            categories_page_href=categories_page_href,
            **self.get_template_variables(),
        )
Esempio n. 6
0
def generate_standalone_page(
    input_file: Path,
    scale: Optional[Union[int, float, Fraction]] = None,
    servings: Optional[int] = None,
    embed_local_links: bool = True,
) -> str:
    """
    Generate a standalone page with a rendered markdown recipe.

    Parameters
    ==========
    input_file : Path
        The file containing the recipe grid markdown file to compile.
    scale : number or None
        If given, scales the recipe by the provided factor (e.g. scale=2 will
        double all quantities). Must not be given if 'servings' is used.
    servings : int or None
        If given, scales the recipe to the specified number of servings. Will
        fail if the recipe does not specify the number of servings it makes in
        its title. Must not be given if 'scale' is used.
    embed_local_links : bool
        If True, links to local files will be replaced by ``data:`` URLs with
        the referenced file contents embedded.
    """
    recipe = compile_recipe_markdown(
        input_file,
        require_title=False,
        require_servings=servings is not None,
    )

    if scale is not None:
        assert servings is None
    elif servings is not None:
        scale = Fraction(servings, recipe.servings)
    else:
        scale = 1

    recipe_html = recipe.render(scale)

    if embed_local_links:
        recipe_html = postprocess_html(
            recipe_html,
            complete_document=True,
            stages=[
                partial(
                    embed_local_links_as_data_urls,
                    source=input_file,
                    root=input_file.parent,
                ),
            ],
        )

    return standalone_recipe_template.render(
        title=recipe.title if recipe.title is not None else "Recipe",
        body=recipe_html,
    )
Esempio n. 7
0
    def test_resolve_local_links_stage(
        self, input_path: Path, make_directory: MakeDirectoryFn
    ) -> None:
        h = HomePage.from_root_directory(
            make_directory({"foo/recipe.md": "# Recipe for 2", "foo/file.txt": "..."}),
        )

        filename_to_asset_paths: MutableMapping[Path, str] = {}
        stage = (
            h.scaled_categories[3]
            .subcategories[0]
            .recipes[0]
            .get_resolve_local_links_stage(
                source=input_path / "foo" / "recipe.md",
                source_to_page_paths={
                    input_path / "README.md": ("/categories/index.html", True),
                    input_path
                    / "foo"
                    / "recipe.md": ("/serves2/foo/recipe.html", True),
                },
                filename_to_asset_paths=filename_to_asset_paths,
            )
        )

        for href, exp_href in [
            # Check directory is correct
            ("recipe.md", "recipe.html"),
            # Check path is right (i.e. uses same number of servings
            ("../README.md", "../index.html"),
            # Check asset paths updated and asset dir is correct
            ("file.txt", "../../assets/foo/file.txt"),
        ]:
            assert postprocess_html(t("a", "foo", href=href), False, [stage]) == t(
                "a", "foo", href=exp_href
            )

        assert filename_to_asset_paths == {
            input_path / "foo" / "file.txt": "/assets/foo/file.txt",
        }

        # Check root is correctly set
        with pytest.raises(LinkToExternalFileError):
            postprocess_html(t("a", "foo", href="../../../foo.bar"), False, [stage])
Esempio n. 8
0
    def test_valid(self, tmp_path: Path) -> None:
        (tmp_path / "bar.txt").open("w").write("foobar")

        assert (postprocess_html(
            t("a", "foo", href="bar.txt"),
            False,
            [
                partial(
                    embed_local_links_as_data_urls,
                    source=tmp_path / "foo.md",
                    root=tmp_path,
                ),
            ],
        ) == t("a", "foo", href="data:text/plain;base64,Zm9vYmFy"))
Esempio n. 9
0
    def test_ignore_external_or_page_local_links(self, tmp_path: Path,
                                                 url: str) -> None:
        html = t("a", "foo", href=url)

        assert (postprocess_html(
            html,
            False,
            [
                partial(
                    embed_local_links_as_data_urls,
                    source=tmp_path / "foo.md",
                    root=tmp_path,
                ),
            ],
        ) == html)
Esempio n. 10
0
 def test_processing(self) -> None:
     # NB: Order of processing steps is checked
     assert (postprocess_html(
         '<a href="foo/bar">Foo-bar</a>',
         False,
         [
             # Capitalise first letter
             lambda t: t.rewrite_links(lambda url: url[0].upper() + url[1:]
                                       ),
             # Swap around "/"
             lambda t: t.rewrite_links(lambda url: "/".join(
                 url.split("/")[::-1])),
             # Return a tree
             lambda t: t,
         ],
     ) == '<a href="bar/Foo">Foo-bar</a>')
Esempio n. 11
0
 def run(
     self,
     html: str,
     tmp_path: Path,
     source: Path,
     from_path: str,
     filename_to_asset_paths: MutableMapping[str, str],
 ) -> str:
     d = tmp_path / "foo" / "bar"
     d.mkdir(parents=True, exist_ok=True)
     (d / "file.txt").open("w").write("Hello!")
     return postprocess_html(
         html,
         False,
         [
             partial(
                 resolve_local_links,
                 source=source,
                 root=tmp_path / "foo",
                 from_path=from_path,
                 source_to_page_paths={
                     tmp_path / "foo" / "bar" / "baz.md":
                     ("/serves2/bar/baz.html", True),
                     tmp_path / "foo" / "bar" / "same.md":
                     ("/serves3/bar/same.html", True),
                     tmp_path / "foo" / "parent.md":
                     ("/serves5/parent.html", True),
                     tmp_path / "foo" / "bar" / "unscaled.md":
                     ("/categories/bar/unscaled.html", False),
                     # Index pages
                     tmp_path / "foo" / "README.md":
                     ("/categories/index.html", True),
                     tmp_path / "foo" / "bar" / "README.md":
                     ("/categories/bar/index.html", True),
                     # Directories
                     tmp_path / "foo": ("/categories/index.html", True),
                     tmp_path / "foo" / "bar":
                     ("/categories/bar/index.html", True),
                 },
                 filename_to_asset_paths=filename_to_asset_paths,
                 assets_dir_path="/static",
             )
         ],
     )
Esempio n. 12
0
def test_add_recipe_scaling_links() -> None:
    html = compile_markdown("# A recipe serving 3").render(Fraction(2, 3))

    assert postprocess_html(
        html,
        False,
        [
            partial(
                add_recipe_scaling_links,
                from_path="/serves2/foo/bar.html",
                scaled_paths={
                    1: "/serves1/foo/bar.html",
                    2: "/serves2/foo/bar.html",
                    3: "/serves3/foo/bar.html",
                    4: "/serves4/foo/bar.html",
                },
                native_servings=3,
            )
        ],
    ) == ('<header><h1 class="rg-title-scalable">A recipe '
          '<span class="rg-serving-count">'
          '<a href="#" class="rg-serving-count-current">'
          'serving <span class="rg-scaled-value">2</span>'
          "</a>"
          "<ul>"
          '<li><a href="../../serves1/foo/bar.html">serving '
          '<span class="rg-scaled-value">1</span></a></li>'
          '<li><a href="bar.html">serving '
          '<span class="rg-scaled-value">2</span></a></li>'
          '<li><a href="../../serves3/foo/bar.html">serving '
          '<span class="rg-scaled-value">3</span></a></li>'
          '<li><a href="../../serves4/foo/bar.html">serving '
          '<span class="rg-scaled-value">4</span></a></li>'
          "</ul>"
          "</span></h1><p>Rescaled from "
          '<span class="rg-original-servings">'
          '<a href="../../serves3/foo/bar.html">3 servings</a></span>.</p>'
          "</header>\n")
Esempio n. 13
0
 def test_fragment_passthrough(self, source: str, exp: str) -> None:
     assert postprocess_html(source, False) == exp
Esempio n. 14
0
 def test_document_passthrough(self, source: str, exp: str) -> None:
     assert postprocess_html(source) == exp