2010-05-20 24 views
7

कई उपयोगिताओं रहे हैं एक अजगर पैकेज और उसके निर्भरता के सभी हो रही है और उन्हें एक ही द्विआधारी कार्यक्रम ग्राहकों के लिए जहाज के लिए आसान है कि में बदल के लिए:एड-ऑन या एक्सटेंशन का समर्थन करने के लिए एक फ़ाइल के रूप में एक पायथन ऐप को बंडल करें? विभिन्न प्रक्रियाओं, सीमाएं और लक्ष्य ऑपरेटिंग सिस्टम के साथ सभी - -

मेरी स्थिति एक कदम आगे जाती है: तीसरे पक्ष के डेवलपर्स मेरे आवेदन के लिए प्लग-इन, एक्सटेंशन या ऐड-ऑन लिखना चाहते हैं। यह निश्चित रूप से एक कठिन सवाल है कि विंडोज़ जैसे प्लेटफ़ॉर्म पर उपयोगकर्ता आसानी से प्लगइन या एडॉन्स को इस तरह से इंस्टॉल करेंगे कि मेरा ऐप आसानी से पता लगा सके कि वे इंस्टॉल किए गए हैं। लेकिन उस मूल प्रश्न से परे एक और है: एक तीसरे पक्ष के डेवलपर अपने एक्सटेंशन को विस्तार से कैसे जोड़ सकते हैं, जो विस्तार से जरूरत है (जो बाइनरी मॉड्यूल, जैसे एलएक्सएमएल हो सकता है) इस तरह से प्लगइन की निर्भरता आयात के लिए उपलब्ध हो सकती है समय जब प्लगइन उपलब्ध हो जाता है।

यह कैसे संपर्क किया जा सकता है? क्या इस एप्लिकेशन को डिस्क पर अपने प्लग-इन क्षेत्र और इसकी अपनी प्लग-इन रजिस्ट्री की आवश्यकता होगी? या क्या सामान्य तंत्र हैं, कि मैं खुद को लिखने से बच सकता हूं, जो एक ऐप को एक निष्पादन योग्य के रूप में वितरित किया जा सकता है जो देखने के लिए और प्लगइन ढूंढता है जो एकल फाइलों के रूप में भी स्थापित होते हैं?

उत्तर

7

आपको एक प्लगइन निर्देशिका प्राप्त करने में सक्षम होना चाहिए कि आपका एप्लिकेशन रनटाइम (या बाद में) स्कैन करता है ताकि प्रश्न में कोड आयात किया जा सके। यहां एक उदाहरण दिया गया है जो नियमित .py या .pyc कोड के साथ काम करना चाहिए जो ज़िप फ़ाइलों के अंदर संग्रहीत प्लगइन के साथ भी काम करता है (इसलिए उपयोगकर्ता केवल 'प्लगइन्स' निर्देशिका में कुछplugin.zip को छोड़ सकते हैं और इसे जादुई रूप से काम कर सकते हैं):

import re, os, sys 
class Plugin(object): 
    """ 
    The base class from which all plugins are derived. It is used by the 
    plugin loading functions to find all the installed plugins. 
    """ 
    def __init__(self, foo): 
     self.foo = foo 
    # Any useful base plugin methods would go in here. 

def get_plugins(plugin_dir): 
    """Adds plugins to sys.path and returns them as a list""" 

    registered_plugins = [] 

    #check to see if a plugins directory exists and add any found plugins 
    # (even if they're zipped) 
    if os.path.exists(plugin_dir): 
     plugins = os.listdir(plugin_dir) 
     pattern = ".py$" 
     for plugin in plugins: 
      plugin_path = os.path.join(plugin_dir, plugin) 
      if os.path.splitext(plugin)[1] == ".zip": 
       sys.path.append(plugin_path) 
       (plugin, ext) = os.path.splitext(plugin) # Get rid of the .zip extension 
       registered_plugins.append(plugin) 
      elif plugin != "__init__.py": 
       if re.search(pattern, plugin): 
        (shortname, ext) = os.path.splitext(plugin) 
        registered_plugins.append(shortname) 
      if os.path.isdir(plugin_path): 
       plugins = os.listdir(plugin_path) 
       for plugin in plugins: 
        if plugin != "__init__.py": 
         if re.search(pattern, plugin): 
          (shortname, ext) = os.path.splitext(plugin) 
          sys.path.append(plugin_path) 
          registered_plugins.append(shortname) 
    return registered_plugins 

def init_plugin_system(cfg): 
    """ 
    Initializes the plugin system by appending all plugins into sys.path and 
    then using load_plugins() to import them. 

     cfg - A dictionary with two keys: 
     plugin_path - path to the plugin directory (e.g. 'plugins') 
     plugins - List of plugin names to import (e.g. ['foo', 'bar']) 
    """ 
    if not cfg['plugin_path'] in sys.path: 
     sys.path.insert(0, cfg['plugin_path']) 
    load_plugins(cfg['plugins']) 

def load_plugins(plugins): 
    """ 
    Imports all plugins given a list. 
    Note: Assumes they're all in sys.path. 
    """ 
    for plugin in plugins: 
     __import__(plugin, None, None, ['']) 
     if plugin not in Plugin.__subclasses__(): 
      # This takes care of importing zipped plugins: 
      __import__(plugin, None, None, [plugin]) 

तो मान लें कि मेरे पास 'प्लगइन' नामक एक निर्देशिका में "foo.py" नामक एक प्लगइन है (जो मेरे ऐप के आधार डीआईआर में है) जो मेरे एप्लिकेशन में एक नई क्षमता जोड़ देगा। सामग्री इस प्रकार दिखाई देंगे:

from plugin_stuff import Plugin 

class Foo(Plugin): 
    """An example plugin.""" 
    self.menu_entry = {'Tools': {'Foo': self.bar}} 
    def bar(self): 
     return "foo plugin!" 

मैं अपने प्लग-इन को प्रारंभ कर सकता है जब मैं बहुत तरह मेरे एप्लिकेशन लॉन्च:

plugin_dir = "%s/plugins" % os.getcwd() 
plugin_list = get_plugins(plugin_dir) 
init_plugin_system({'plugin_path': plugin_dir, 'plugins': plugin_list}) 
plugins = find_plugins() 
plugin_menu_entries = [] 
for plugin in plugins: 
    print "Enabling plugin: %s" % plugin.__name__ 
    plugin_menu_entries.append(plugin.menu_entry)) 
add_menu_entries(plugin_menu_entries) # This is an imaginary function 

कि जब तक काम करना चाहिए के रूप में प्लगइन या तो एक .py या .pyc है फ़ाइल (मान लीजिए कि यह मंच में मंच के लिए बाइट-संकलित है)। यह एक ही नियम के साथ एक ज़िप फ़ाइल के अंदर init .py या के साथ एक निर्देशिका के अंदर स्टैंडअलोन फ़ाइल या अंदर हो सकती है।

मुझे यह काम कैसे पता चलेगा? इस तरह मैंने PyCI में प्लगइन लागू किए। पीईसीआई एक वेब एप्लिकेशन है लेकिन इसका कोई कारण नहीं है कि यह विधि नियमित ओएल 'जीयूआई के लिए क्यों काम नहीं करेगी। ऊपर दिए गए उदाहरण के लिए मैंने एक प्लगइन ऑब्जेक्ट वेरिएबल के साथ एक काल्पनिक add_menu_entries() फ़ंक्शन का उपयोग करना चुना है जिसका प्रयोग आपके जीयूआई मेनू में प्लगइन के तरीकों को जोड़ने के लिए किया जा सकता है।

उम्मीद है कि यह उत्तर आपको अपनी प्लगइन प्रणाली बनाने में मदद करेगा। यदि आप यह देखना चाहते हैं कि यह कैसे कार्यान्वित किया गया है, तो मैं आपको पीसीसीआई स्रोत कोड डाउनलोड करने और plugins_enabled निर्देशिका में प्लगइन_utils.py और उदाहरण प्लगइन को देखने की सलाह देता हूं।

+0

पीईसीएल के दृष्टिकोण को इंगित करने के लिए धन्यवाद! इसके प्लगइन लेखक क्या करते हैं जब वे निर्भरता को बंडल करना चाहते हैं, जैसे कि "एलएक्सएमएल" लाइब्रेरी जो मेरे प्रश्न का उल्लेख है? क्या होगा यदि दो प्लगइन्स दोनों को "lxml" की आवश्यकता है लेकिन प्रत्येक बंडल थोड़ा अलग संस्करण है? और क्या होगा यदि "एलएक्सएमएल" में बाइनरी पार्ट्स हैं जो विंडोज़ पर डीएलएल उत्पन्न करेंगे लेकिन लिनक्स पर भी। –

+0

प्लगइन लेखकों में उनकी प्लगइन के मूल पथ में जो भी निर्भरता चाहिए उन्हें शामिल कर सकते हैं। यह काम करता है क्योंकि आयात किए जाने से ठीक पहले प्लगइन का पथ sys.path में जोड़ा जाता है। एकमात्र चेतावनी यह होगी कि यदि प्लगइन को प्लेटफ़ॉर्म-विशिष्ट निर्भरता की आवश्यकता होती है तो प्लगइन लेखक को प्रत्येक आर्किटेक्चर के लिए एक पैकेज होना होगा, जिसे वे समर्थन देने के इच्छुक हैं। मैं यह भी उल्लेख करना चाहूंगा कि पीईसीआई में प्लगइन की निर्देशिका के भीतर से फ़ाइलों को पुनर्प्राप्त करने के लिए विधियों (प्लगइन() में) शामिल हैं। इसलिए यदि कोई प्लगइन स्थैतिक सामग्री का उपयोग करता है तो प्लगइन एक ज़िप फ़ाइल में होने पर भी इसे परोसा जा सकता है। –

0

यहां एक पाइथन ऐप का एक और उदाहरण है जो प्लगइन का उपयोग करता है: OpenSTV। यहां, प्लगइन्स केवल पायथन मॉड्यूल ही हो सकते हैं।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^