免费观看又色又爽又黄的小说免费_美女福利视频国产片_亚洲欧美精品_美国一级大黄大色毛片

如何在自己的應用上使用Stevedore實現插件的動態管理

如何在自己的應用上使用Stevedore實現插件的動態管理,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

我們提供的服務有:成都網站建設、網站制作、微信公眾號開發、網站優化、網站認證、蘇仙ssl等。為近1000家企事業單位解決了網站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的蘇仙網站制作公司

一步一步地演示如何定義插件,然后在您的應用程序中使用裝載和使用這些插件。

命名插件指南

Stevedore使用setuptools入口點來定義和加載插件。 entry point是指在Python模塊或包中定義的命名對象的標準方法。 名稱可以是對任何類、函數或實例的引用,只要它是在導入包含模塊的時候創建的。 ( 即:它需要一個模塊級的全局 )

名稱和命名空間

entry point使用命名空間中的名稱進行注冊。

entry point名稱通常被認為是用戶可見的。  例如:們經常出現在配置文件中,這是啟動驅動程序的地方。 因為它們是公開的,所以在保持描述性的同時,名稱通常盡可能短。 如: 數據庫驅動程序插件名可能是MySQL、postgresql、sqlite等。

另一方面,名稱空間是一個實現細節,雖然它們是開發人員知道的,但它們通常不會公開給用戶。 名稱空間的命名語法看起來很像Python的包語法(a.b.c),但是名稱空間并不對應于Python包。 為entry point命名空間使用Python包名是一種簡單的方法來確保唯一的名稱,但這完全不是必需的。 entry point 的主要特征是可以跨包發現它們。 這意味著一個插件可以與應用程序完全分開開發和安裝, 只要他們同意命名空間和API。

每個名稱空間都由使用該插件的代碼所擁有,并用于搜索 entry points 。 entry point的名稱通常是由插件所擁有的,但是它們也可以通過命名鉤子的代碼來定義(看 HookManager) 。 在給定的 distribution 中,entry point的名稱必須是唯一的,但在名稱空間中不一定是唯一的 。

創建插件

經過反復試驗,我發現定義API的最簡單方法是遵循以下步驟:

  1. 使用abc模塊創建一個基本抽象類來定義API插件所需的行為。 開發人員不需要從基類中子類化,但是它提供了一種方便的方式來記錄API,并且使用抽象基類使代碼保持可靠。

  2. 通過子類化基類并實現所需的方法來創建插件。

  3. 通過結合應用程序的名稱(或庫)和API的名稱,為每個API定義一個惟一的名稱空間。 保持簡單, 例如: “cliff.formatters” or “ceilometer.pollsters.compute” 。

示例插件集

本教程中的示例程序將創建一個帶有幾個數據格式化程序的插件集,比如命令行程序可以使用什么來準備將數據打印到控制臺。 每個格式化程序都將作為輸入,使用字符串鍵和內置的數據類型作為值。 它將返回作為輸出的迭代器,該迭代器根據所使用的特定格式化程序的規則生成數據結構的數據結構。 formatter的構造函數允許調用者指定輸出應該具有的最大寬度。

一個插件的基類

上面的步驟1是為需要由每個插件實現的API定義一個抽象基類。

# stevedore/example/base.py
import abc

import six


@six.add_metaclass(abc.ABCMeta)
class FormatterBase(object):
    """Base class for example plugin used in the tutorial.
    """

    def __init__(self, max_width=60):
        self.max_width = max_width

    @abc.abstractmethod
    def format(self, data):
        """Format the data and return unicode text.

        :param data: A dictionary with string keys and simple types as
                     values.
        :type data: dict(str:?)
        :returns: Iterable producing the formatted text.
        """

構造函數是一個具體的方法,因為子類不需要覆蓋它,但是format()方法沒有做任何有用的事情,因為沒有可用的默認實現。

繼承并實現插件基類

下一步是創建幾個帶有format()的具體實現的插件類。 一個簡單的示例格式化程序在一行中使用每個變量名和值生成輸出。

# stevedore/example/simple.py
from stevedore.example import base


class Simple(base.FormatterBase):
    """A very basic formatter.
    """

    def format(self, data):
        """Format the data and return unicode text.

        :param data: A dictionary with string keys and simple types as
                     values.
        :type data: dict(str:?)
        """
        for name, value in sorted(data.items()):
            line = '{name} = {value}\n'.format(
                name=name,
                value=value,
            )
            yield line

還有很多其他的格式化選項,但是這個例子將給我們提供足夠的工作來演示注冊和使用插件。

注冊插件

要使用setuptools entry point,必須使用setuptools打包應用程序或庫。 構建和打包過程生成元數據,這些元數據可以在安裝之后找到,以找到每個python發行版提供的插件。

entry point必須被聲明為屬于特定的名稱空間,因此我們需要在進行下一步之前選擇一個。 這些插件是來自于 stevedore 的例子, 因此我將使用 “stevedore.example.formatter”名稱空間。 現在可以在包裝說明中提供所有必要的信息:

# stevedore/example/setup.py
from setuptools import setup, find_packages

setup(
    name='stevedore-examples',
    version='1.0',

    description='Demonstration package for stevedore',

    author='Doug Hellmann',
    author_email='doug@doughellmann.com',

    url='http://git.openstack.org/cgit/openstack/stevedore',

    classifiers=['Development Status :: 3 - Alpha',
                 'License :: OSI Approved :: Apache Software License',
                 'Programming Language :: Python',
                 'Programming Language :: Python :: 2',
                 'Programming Language :: Python :: 2.7',
                 'Programming Language :: Python :: 3',
                 'Programming Language :: Python :: 3.4',
                 'Intended Audience :: Developers',
                 'Environment :: Console',
                 ],

    platforms=['Any'],

    scripts=[],

    provides=['stevedore.examples',
              ],

    packages=find_packages(),
    include_package_data=True,

    entry_points={
        'stevedore.example.formatter': [
            'simple = stevedore.example.simple:Simple',
            'plain = stevedore.example.simple:Simple',
        ],
    },

    zip_safe=False,
)

底部最重要的地方就是給setup()設置entry point。 該值是一個字典,將插件的名稱空間映射到它們的定義列表。 列表中的每一項都應該是一個帶有name=module:importable的形式,此名對用戶是可見的, module 是模塊的Python導入引用 , importable 是可以從模塊內部導入的名稱 ,如下:

'simple = stevedore.example.simple:Simple',
            'plain = stevedore.example.simple:Simple',
        ],
    },

    zip_safe=False,
)

在本例中,有兩個插件注冊了。 上面定義的簡單插件和一個普通的插件,它只是簡單插件的別名。

setuptools元數據

在構建期間, setuptools  為軟件包復制 entry point定義 到 “.egg-info” 目錄的文件中。例如,stevedore例子的entry point 位于 stevedore.egg-info/entry_points.txt ,內容如下:

[stevedore.example.formatter]
simple = stevedore.example.simple:Simple
plain = stevedore.example.simple:Simple

[stevedore.test.extension]
t2 = stevedore.tests.test_extension:FauxExtension
t1 = stevedore.tests.test_extension:FauxExtension

pkg_resources 使用 entry_points.txt 從已安裝到環境中的所有軟件中查找插件。 你不應該修改這些文件, 除了更改setup.py中的entry point列表。

在其他包中添加插件

插件的吸引力除了 entry points 之外 ,還有就是它們可以獨立于應用程序進行分發。 setuptools   命名空間用來區分插件與Python源代碼名稱空間不同。 通常使用一個插件名稱空間,前綴是加載插件的應用程序或庫的名稱,以確保它是惟一的,但是這個名稱對于Python包的代碼應該如何生存沒有任何影響。

例如, 我們可以添加一個formatter插件的另一個實現,它可以生成一個 reStructuredText field list

# stevedore/example2/fields.py
import textwrap

from stevedore.example import base


class FieldList(base.FormatterBase):
    """Format values as a reStructuredText field list.

    For example::

      : name1 : value
      : name2 : value
      : name3 : a long value
          will be wrapped with
          a hanging indent
    """

    def format(self, data):
        """Format the data and return unicode text.

        :param data: A dictionary with string keys and simple types as
                     values.
        :type data: dict(str:?)
        """
        for name, value in sorted(data.items()):
            full_text = ': {name} : {value}'.format(
                name=name,
                value=value,
            )
            wrapped_text = textwrap.fill(
                full_text,
                initial_indent='',
                subsequent_indent='    ',
                width=self.max_width,
            )
            yield wrapped_text + '\n'

新的插件可以使用 setup.py來打包

# stevedore/example2/setup.py
from setuptools import setup, find_packages

setup(
    name='stevedore-examples2',
    version='1.0',

    description='Demonstration package for stevedore',

    author='Doug Hellmann',
    author_email='doug@doughellmann.com',

    url='http://git.openstack.org/cgit/openstack/stevedore',

    classifiers=['Development Status :: 3 - Alpha',
                 'License :: OSI Approved :: Apache Software License',
                 'Programming Language :: Python',
                 'Programming Language :: Python :: 2',
                 'Programming Language :: Python :: 2.7',
                 'Programming Language :: Python :: 3',
                 'Programming Language :: Python :: 3.4',
                 'Intended Audience :: Developers',
                 'Environment :: Console',
                 ],

    platforms=['Any'],

    scripts=[],

    provides=['stevedore.examples2',
              ],

    packages=find_packages(),
    include_package_data=True,

    entry_points={
        'stevedore.example.formatter': [
            'field = stevedore.example2.fields:FieldList',
        ],
    },

    zip_safe=False,
)

  新插件是在一個叫stevedore-examples2的獨立包

setup(
    name='stevedore-examples2',

這個插件也是注冊在stevedore.example.formatter命名空間里的

'stevedore.example.formatter': [
            'field = stevedore.example2.fields:FieldList',
        ],
    },

當插件名稱空間被掃描時,所有在當前 PYTHONPATH 的軟件包會被檢測到, 來自第二個軟件包的 entry point 能夠被找到并加載,而應用程序并不需要知道插件具體安裝在哪里。

加載插件

在使用插件時有幾種不同的啟用調用方式,依賴于你的需要。

加載驅動

最常用的方式是插件作用單獨的驅動程序。這種情況,一般是有多個插件選擇但是只有一個需要加載和調用。 DriverManager 能夠支持這種方式。下面例子就是使用 DriverManager 方式來實現

# stevedore/example/load_as_driver.py
from __future__ import print_function

import argparse

from stevedore import driver


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'format',
        nargs='?',
        default='simple',
        help='the output format',
    )
    parser.add_argument(
        '--width',
        default=60,
        type=int,
        help='maximum output width for text',
    )
    parsed_args = parser.parse_args()

    data = {
        'a': 'A',
        'b': 'B',
        'long': 'word ' * 80,
    }

    mgr = driver.DriverManager(
        namespace='stevedore.example.formatter',
        name=parsed_args.format,
        invoke_on_load=True,
        invoke_args=(parsed_args.width,),
    )
    for chunk in mgr.driver.format(data):
        print(chunk, end='')

manager 接收插件的命名空間和名字作為參數,用他們來找插件。因為 invoke_on_load 調用true,它會調用對象加載。在這種情況對象是被注冊為 formatter 的插件類。 invoke_args 是會被傳進類構造器的可選參數, 用于設置最大寬度參數。

mgr = driver.DriverManager(
        namespace='stevedore.example.formatter',
        name=parsed_args.format,
        invoke_on_load=True,
        invoke_args=(parsed_args.width,),
    )

manager 被創建之后, 它通過調用注冊為插件的代碼返回一個對象。 該對象是實際的驅動程序,在本例中是來自插件的formatter類的實例。 可以通過管理器的驅動程序訪問單個驅動程序,然后可以直接調用它的方法 。

for chunk in mgr.driver.format(data):
        print(chunk, end='')

運行示例程序會產生這個輸出

$ python -m stevedore.example.load_as_driver a = A
b = B
long = word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

$ python -m stevedore.example.load_as_driver field
: a : A
: b : B
: long : word word word word word word word word word word
    word word word word word word word word word word word
    word word word word word word word word word word word
    word word word word word word word word word word word
    word word word word word word word word word word word
    word word word word word word word word word word word
    word word word word word word word word word word word
    word word word word

$ python -m stevedore.example.load_as_driver field --width 30
: a : A
: b : B
: long : word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word

加載擴展

另一個常見的用例是一次加載多個擴展, 然后調用他們。 其他幾個管理器類支持這種調用模式 ,包括: ExtensionManager, NamedExtensionManager, and EnabledExtensionManager.

# stevedore/example/load_as_extension.py
from __future__ import print_function

import argparse

from stevedore import extension


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--width',
        default=60,
        type=int,
        help='maximum output width for text',
    )
    parsed_args = parser.parse_args()

    data = {
        'a': 'A',
        'b': 'B',
        'long': 'word ' * 80,
    }

    mgr = extension.ExtensionManager(
        namespace='stevedore.example.formatter',
        invoke_on_load=True,
        invoke_args=(parsed_args.width,),
    )

    def format_data(ext, data):
        return (ext.name, ext.obj.format(data))

    results = mgr.map(format_data, data)

    for name, result in results:
        print('Formatter: {0}'.format(name))
        for chunk in result:
            print(chunk, end='')
        print('')

ExtensionManager與 DriverManager 的創建略有不同,因為它不需要提前知道要加載哪個插件。 它加載了它找到的所有插件。

mgr = extension.ExtensionManager(
        namespace='stevedore.example.formatter',
        invoke_on_load=True,
        invoke_args=(parsed_args.width,),
    )

調用插件,使用 map() 方法,傳遞一個回調方法來調用每個插件。 format_data() 接收兩個參數。

def format_data(ext, data):
        return (ext.name, ext.obj.format(data))

    results = mgr.map(format_data, data)

被傳進 format_data()Extension 參數由 stevedore 定義的一個類。它包含插件的名字,由 pkg_resources 返回的 EntryPoint 和插件自己。當 invoke_on_load 是true時, Extension 將會有個對象屬性, 該屬性包含在調用插件時返回的值。 map() 返回回調函數返回的值序列。 在這個案例上, format_data() 返回一個元組,此元組包含一個插件名和一個 iterable。 在處理結果時,每個插件的名稱都被打印出來,然后是格式化的數據。

for name, result in results:
        print('Formatter: {0}'.format(name))
        for chunk in result:
            print(chunk, end='')
        print('')

加載插件的順序是未定義的,并且依賴于在導入路徑上找到的訂單包以及讀取元數據文件的方式。 如果使用了訂單擴展名 ,嘗試用 NamedExtensionManager

$ python -m stevedore.example.load_as_extension --width 30
Formatter: simple
a = A
b = B
long = word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

Formatter: field
: a : A
: b : B
: long : word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word word word word word
    word

Formatter: plain
a = A
b = B
long = word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

為什么不直接調用插件

使用一個單獨的可調用的參數 map() ,而不是直接調用插件,這將導致應用程序代碼和插件之間的分離。 這種分離的好處體現在應用程序代碼設計和插件API設計中。

如果map()直接調用插件,每個插件都必須是可調用的。 這將意味著一個單獨的命名空間,它實際上只是一個插件的方法。 通過使用一個單獨的可調用的參數,插件API不需要匹配應用程序中任何特定的用例。 這使您可以創建一個更細粒度的API,使用更多的方法可以以不同的方式調用以實現不同的目標。

關于如何在自己的應用上使用Stevedore實現插件的動態管理問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注創新互聯行業資訊頻道了解更多相關知識。

名稱欄目:如何在自己的應用上使用Stevedore實現插件的動態管理
網址分享:http://m.newbst.com/article22/jococc.html

成都網站建設公司_創新互聯,為您提供網站導航網站建設自適應網站企業網站制作網站改版

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

微信小程序開發