【问题标题】:Designing a python plugin system设计一个python插件系统
【发布时间】:2016-02-20 20:49:17
【问题描述】:

我目前正在开发一个处理metrics 的用户指定列表(在文件中)的系统;度量标准是一些字符串和一些关于如何执行特定计算的逻辑的集合。 python 脚本会定期在 linux 服务器上运行并查询文件。

指标应该易于扩展,因此我正在寻找某种模块化方法来将计算代码封装到指标规范中。没有创建一个配置解析系统,这将严重限制计算的复杂性,我正在寻找一个插件系统,其中每个指标的计算都可以在 python 代码中指定。

例如,这里是指标的核心单位。

db = "database0"
mes = "measurement0"
tags = ["alpha", "beta", "delta"]
calculation: (accepts parameters a and b)
    for item in a:
        b.add(a)
    return b

python 脚本需要从文件中获取每个指标,访问它们的字符串字段并执行它们的计算代码,将相同的参数传递给每个。

我目前有一个糟糕的方法;在一个单独的 python 文件中,我定义了一个基类,每个新指标都将对其进行扩展。就是这个样子

class Metric(object):
    def __init__(self, database_name, measurement_name, classad_tags, classad_fields=[]):
        """
        A specification of a metric.
        Arguments:
            database_name    - name of the influx DB (created if doesn't exist)
            measurement_name - measurement name with which to label metric in DB
            classad_tags     - list of classad fields (or mock ads) which will
                               segregate values at a time for this metric, becoming
                               tags in the influxDB measurement
            classad_fields   - any additional job classad fields that this metric will
                               look at (e.g. for metric value calculation).
                               These must be declared so that the daemon can fetch any
                               needed classads from condor
        """
        self.db = database_name
        self.mes = measurement_name
        self.tags = classad_tags
        self.fields = classad_fields

    def calculate_at_bin(self, time_bin, jobs):
        """
        """

        raise ReferenceError("")


"""
--------------------------------------------------------------------------------------
"""


class metric0(Metric):
    def __init__(self):

        db = 'testdb'
        mes = 'testmes0'
        tags = ['Owner']
        fields = []
        super(metric0, self).__init__(db, mes, tags, fields)

    def calculate_at_bin(self, time_bin, jobs):

        for job in jobs:
            if job.is_idle_during(time_bin.start_time, time_bin.end_time):
                time_bin.add_to_sum(1, job.get_values(self.tags))
        return time_bin.get_sum()

要创建新指标,您需要创建Metric 的新子类,将字符串字段传递给超级构造函数并覆盖calculate_at_bin 方法。在主 python 脚本中,我创建了每个指标的实例,其中包含...

metrics = [metric() for metric in vars()['Metric'].__subclasses__()]

但是,这显然很糟糕。 它涉及完全任意但必须唯一的子类名称 (metric0) 和与指标无关的代码(例如类定义、调用构造函数等)。

我还可以想象另一种糟糕的方法,比如带有一些代码的配置文件会得到eval'd,但我也想避免这种情况。

请注意,无需担心安全性或代码注入;这个系统真的只会被我亲自指导的少数人使用。 所以;我该怎么办?

【问题讨论】:

  • 在 stackoverflow 标题中使用“最佳实践”会使人容易受到路过投票的影响

标签: python plugins


【解决方案1】:

您是否考虑过将度量标准的代码作为可导入模块,提供calculate_at_bin 函数作为“接口”,将所有此类模块放在一个目录中,然后动态导入它们?将消除可能的名称冲突问题,如果不担心安全性,至少处理起来非常简单......

【讨论】:

  • 您是否建议将每个指标放入一个单独的文件中,并创建一些实例变量,如 db、mes.. 并定义计算函数?我想我希望将指标放在一个文件中(这似乎是狡猾和临时的;当然有一些优雅的方法可以做到这一点)
  • 每个指标都在它自己的文件中,并在可能的情况下共享数据库等。这将很容易扩展(添加新的模块文件,无需修改,即使在语法错误时也能进行简单的异常处理),以及内省(基本上打电话给os.listdir() 会很优雅。它也解决了你提到的所有可怕的事情。很抱歉误解了你。
  • 我不能每个指标都有一个文件,除非它们都在一个文件夹中,这在扩展时会遇到问题(它们需要全部添加到 .__init__)。不确定“如果可能,共享数据库等”是什么意思。你的意思是我可以用os.listdir() 做什么?如何使用它在隔离的命名空间中执行 python 文件?
  • 是的,都在一个文件夹中。不,它们不必添加到__init__.pyos.listdir() 旨在收集该文件夹中的所有(公制)模块。再次抱歉,如果这种方法不符合您的需求。这只是解决问题中列出的缺陷的建议。
  • 文件名仍然是完全任意的,因此不直观。所以为了澄清,你提议使用os.lostdir(),字符串操作python模块名称以便能够使用importlib导入它们?我想相信还有一种更优雅的方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 2015-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多