# Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. import hashlib import os from pathlib import Path from typing import List from urllib.parse import quote, urlencode import requests from docutils import nodes from docutils.parsers.rst import Directive, directives from docutils.parsers.rst.directives.images import Image from docutils.statemachine import StringList from sphinx.util.docutils import SphinxDirective _THIS_DIR = Path(__file__).parent # Color palette from PyTorch Developer Day 2021 Presentation Template YELLOW = "F9DB78" GREEN = "70AD47" BLUE = "00B0F0" PINK = "FF71DA" ORANGE = "FF8300" TEAL = "00E5D1" GRAY = "7F7F7F" def _get_cache_path(key, ext): filename = f"{hashlib.sha256(key).hexdigest()}{ext}" cache_dir = _THIS_DIR / "gen_images" cache_dir.mkdir(parents=True, exist_ok=True) return cache_dir / filename def _download(url, path): response = requests.get(url) response.raise_for_status() with open(path, "wb") as file: file.write(response.content) def _fetch_image(url): path = _get_cache_path(url.encode("utf-8"), ext=".svg") if not path.exists(): _download(url, path) return os.sep + str(path.relative_to(_THIS_DIR)) def _get_relpath(target, base): target = os.sep + target base = os.sep + base target_path, filename = os.path.split(target) rel_path = os.path.relpath(target_path, os.path.dirname(base)) return os.path.normpath(os.path.join(rel_path, filename)) class BaseShield(Image, SphinxDirective): def run(self, params, alt, section) -> List[nodes.Node]: url = f"https://img.shields.io/static/v1?{urlencode(params, quote_via=quote)}" path = _fetch_image(url) self.arguments = [path] self.options["alt"] = alt if "class" not in self.options: self.options["class"] = [] self.options["class"].append("shield-badge") target = _get_relpath("supported_features.html", self.env.docname) self.options["target"] = f"{target}#{section}" return super().run() _CARDLIST_START = """ .. raw:: html

""" _CARD_TEMPLATE = """ .. raw:: html """ _CARDLIST_END = """ .. raw:: html
""" class CustomCardStart(Directive): def run(self): para = nodes.paragraph() self.state.nested_parse( StringList(_CARDLIST_START.split("\n")), self.content_offset, para ) return [para] class CustomCardItem(Directive): option_spec = { "header": directives.unchanged, "image": directives.unchanged, "link": directives.unchanged, "card_description": directives.unchanged, "tags": directives.unchanged, } def run(self): for key in ["header", "card_description", "link"]: if key not in self.options: raise ValueError(f"Key: `{key}` is missing") header = self.options["header"] link = self.options["link"] card_description = self.options["card_description"] tags = self.options.get("tags", "") if "image" in self.options: image = "" else: image = "_static/img/thumbnails/default.png" card_rst = _CARD_TEMPLATE.format( header=header, image=image, link=link, card_description=card_description, tags=tags, ) card_list = StringList(card_rst.split("\n")) card = nodes.paragraph() self.state.nested_parse(card_list, self.content_offset, card) return [card] class CustomCardEnd(Directive): def run(self): para = nodes.paragraph() self.state.nested_parse( StringList(_CARDLIST_END.split("\n")), self.content_offset, para ) return [para]