跳转到主要内容

Python对象的可扩展HTML表示。

项目描述

hrepr

hrepr 为Python对象输出HTML/美观表示。

✅ 列表、字典、数据类、布尔值等的漂亮、多彩的表示
✅ 无与伦比的扩展性和可配置性
✅ 处理递归数据结构
✅ 与Jupyter笔记本兼容

我建议研究示例文件来学习 hrepr

  • python examples/exhibit.py > exhibit.html(然后查看HTML文件)

还可以查看位于 examples/Basics.ipynb 的Jupyter笔记本,但请注意,GitHub由于注入的样式/脚本无法正确显示它。

安装

pip install hrepr

用法

from hrepr import hrepr
obj = {'potatoes': [1, 2, 3], 'bananas': {'cantaloups': 8}}

# Print the HTML representation of obj
print(hrepr(obj))

# Wrap the representation in <html><body> tags and embed the default
# css style files in a standalone page, which is saved to obj.html
hrepr.page(obj, file="obj.html")

在Jupyter笔记本中,您可以从任何单元格返回 hrepr(obj),它将显示其表示。您还可以编写 display_html(hrepr(obj))

自定义表示

可以使用以下三种方法定义对象的自定义表示(不需要定义所有这些,只需与您的案例相关的那些即可)

  • __hrepr__(self, H, hrepr) 返回常规HTML表示。
    • 使用 H.span["some-class"](some-content, some_attr=some_value) 生成HTML。
    • 使用 hrepr(self.x) 生成子字段 x 的表示。
    • hrepr.config 包含在顶级调用 hrepr 中提供的任何关键字参数。例如,如果您调用 hrepr(obj, blah=3),则 hrepr.config.blah == 3 在所有后续调用 __hrepr__ 中(所有键的默认值是 None)。
  • __hrepr_short__(self, H, hrepr) 返回一个 表示,理想情况下为固定大小。
    • 当达到最大深度或出现重复引用时,该方法输出的结果被使用。
    • 仅包含必要的信息。简短意味着简洁。
  • __hrepr_resources__(cls, H) 是一个 类方法,它返回该类所有实例共有的资源(通常是一个样式表或脚本)。
    • 生成页面时,资源将放入 <head> 中。
    • 你可以返回一个资源列表。

不需要依赖 hrepr

例如

class Person:
    def __init__(self, name, age, job):
        self.name = name
        self.age = age
        self.job = job

    @classmethod
    def __hrepr_resources__(cls, H):
        # Note: you might need to add "!important" next to some rules if
        # they conflict with defaults from hrepr's own CSS.
        return H.style("""
            .person {
                background: magenta !important;
                border-color: magenta !important;
            }
            .person-short { font-weight: bold; color: green; }
        """)

    def __hrepr__(self, H, hrepr):
        # hrepr.make.instance is a helper to show a table with a header that
        # describes some kind of object
        return hrepr.make.instance(
            title=self.name,
            fields=[["age", self.age], ["job", self.job]],
            delimiter=" ↦ ",
            type="person",
        )

    def __hrepr_short__(self, H, hrepr):
        return H.span["person-short"](self.name)

引用

hrepr 可以处理循环引用。此外,如果结构中找到多个相同对象,则只打印第一个出现的完整表示,其余的将是一个数字引用,映射到对象的简短表示。它看起来像这样

配置键 shortrefsnorefs 控制引用的表示

当存在循环引用时,忽略 norefs

HTML生成

使用 __hrepr__ 方法的 H 参数生成HTML,或者导入它并直接使用。

from hrepr import H
html = H.span["bear"](
    "Only ", H.b("YOU"), " can prevent forest fires!",
    style="color: brown;"
)
print(html)
# <span class="bear" style="color: brown;">Only <b>YOU</b> can prevent forest fires!</span>

H 可以逐步构建:如果您有一个元素,您可以调用它以添加子元素,索引它以添加类,等等。例如

from hrepr import H
html = H.span()
html = html("Only ")
html = html(style="color: brown;")["bear"]
html = html(H.b("YOU"), " can prevent forest fires!")
print(html)
# <span class="bear" style="color: brown;">Only <b>YOU</b> can prevent forest fires!</span>

这可以很方便地稍微调整生成的HTML。例如,hrepr(obj)["fox"] 将将类 fox 添加到对象的表示中。

辅助工具

  • hrepr.make.instance(title, fields, delimiter=None, type=None):将字段格式化为类似于数据类的形式,标题在最上方。
  • hrepr.make.bracketed(body, start, end, type=None):使用指定的起始/结束括号格式化正文。

使用JavaScript库

函数 J 允许您创建JavaScript表达式。如果表达式以HTML元素作为参数,您可以创建一个并使用 returns() 语句传递它,该语句告诉hrepr将其插入到 J() 表达式所在的位置。

例如,您可以加载Plotly并创建一个像这样的图表

from hrepr import H, J, returns

def plot(data):
    Plotly = J(src="https://cdn.plot.ly/plotly-latest.min.js").Plotly
    return Plotly.newPlot(
        returns(H.div()),
        [{"x": list(range(len(data))), "y": list(data)}],
    )

print(plot([math.sin(x / 10) for x in range(100)]).as_page())

上面的代码将

  • 将指定的脚本放入页面的 <head> 元素中(这就是为什么需要 as_page() 调用来使其工作)。
  • 插入一些hrepr库代码。
  • J() 调用处插入一个 <div>,如 returns(H.div()) 所指定,并带有自动生成的ID。
  • 在全局命名空间中获取 Plotly.newPlot 函数。
  • 用第一个参数(作为 div 元素)和任何其他给定的参数调用它(只要它们可以序列化为JSON)。

它看起来像这样

您当然可以在 JH 内嵌套 J,例如 H.body(H.h1(...), H.div(J(...))),只要您喜欢,这样您可以轻松地组合多个库。请注意,如果没有 returns() 参数的JavaScript,它可能需要返回一个HTML元素以插入其代替(将自动创建占位符)。

小心处理 J 对象:由于它们覆盖了 __getattr____call__,它们几乎永远不会引发异常,并且很容易意外生成不正确的表达式。

模块

另一个例子,这次使用ESM(模块)

cystyle = [{"selector": "node","style": {"background-color": "#800", "label": "data(id)"},},{"selector": "edge","style": {"width": 3,"line-color": "#ccc","target-arrow-color": "#ccc","target-arrow-shape": "triangle","curve-style": "bezier"}}]

cytoscape = J(module="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.23.0/cytoscape.esm.min.js")
j = cytoscape(
    container=returns(H.div(style="width:500px;height:500px;border:1px solid black;")),
    elements=[
        {"data": {"id": "A"}},
        {"data": {"id": "B"}},
        {"data": {"id": "C"}},
        {"data": {"source": "A", "target": "B"}},
        {"data": {"source": "B", "target": "C"}},
        {"data": {"source": "C", "target": "A"}},
    ],
    style=cystyle,
    layout={"name": "cose"},
)
print(j.as_page())

上面的代码将像前面的例子一样工作,但有以下区别

  • 导入指定的模块。
  • 所有关键字参数都打包成一个对象,该对象将作为最后一个(在这种情况下,唯一的)参数传递给模块的默认导出。

如果您想使用非默认导出,请使用 namespace= 而不是 module=。例如,如果您想使用JavaScript导入 import {fn} from "xxx",请使用 J(namespace="xxx").fn(...)

自定义hrepr

混合

如果您想真正自定义 hrepr,可以使用混入(mixins)。它们看起来像一点黑魔法,但它们足够简单。

# ovld is one of the dependencies of hrepr
from ovld import ovld, extend_super, has_attribute, OvldMC
from hrepr import hrepr

class MyMixin(metaclass=OvldMC):
    # Change the representation of integers

    @extend_super
    def hrepr_resources(self, cls: int):
        # Note: in hrepr_resources, cls is the int type, not an integer
        return self.H.style(".my-integer { color: fuchsia; }")

    @extend_super
    def hrepr(self, n: int):
        return self.H.span["my-integer"]("The number ", str(n))

    # Specially handle any object with a "quack" method

    def hrepr(self, duck: has_attribute("quack")):
        return self.H.span("🦆")

规则的注释可以是类型、ovld.has_attribute,或者任何用 ovld.meta 装饰器包装的函数,只要该函数在类上操作。有关更多信息,请参阅 ovld 的文档。

是的,您可以在类内部多次定义 hrepr,只要它们具有不同的注释并且您继承自 Hrepr。您也可以以相同的方式定义 hrepr_shorthrepr_resources

后处理器

hrepr 可以提供一个后处理器,该后处理器在任意对象的表示上被调用。您可以使用它来执行诸如突出特定对象之类的操作。

from hrepr import H

style = H.style(".highlight { border: 3px solid red !important; }")

def highlight(x):
    def postprocess(element, obj, hrepr):
        if obj == x:
            # Adds the "highlight" class and attaches a style
            return element["highlight"].fill(resources=style)
        else:
            return element

    return postprocess

hrepr([1, 2, [3, 4, 2]], postprocess=highlight(2))

hrepr 变体

将所有这些放在一起,您可以为 hrepr 创建一个 变体

hrepr2 = hrepr.variant(mixins=MyMixin, postprocess=highlight(2))
hrepr2([1, 2, 3])  # Will use the mixins and postprocessor

配置 hrepr 函数本身

或者,您也可以配置主要的 hrepr

hrepr.configure(mixins=MyMixin, postprocess=highlight(2))

但请注意,与变体不同,上述操作将修改 hrepr 用于其他所有内容。

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分发

hrepr-0.8.0.tar.gz (2.4 MB 查看哈希值)

上传时间

构建分发

hrepr-0.8.0-py3-none-any.whl (24.4 kB 查看哈希值)

上传时间 Python 3

由以下支持