def run(self): with open(path.join('config', self.env + '.yaml')) as cfg_file: cfg = yaml_load(cfg_file) bot = Bot(cfg['token']) PluginManager.load(bot, cfg) bot.run(debug=self.debug, reload=False)
def test_load_nonexistent_plugin_fails(self): name = 'nonexistent' plugins = [name] manager = PluginManager(Mock()) failed_plugins = manager.load(plugins) assert failed_plugins == plugins assert manager.plugins == {}
def test_unload_plugins_never_loaded_plugin_fails(self): name = 'test_never_loaded_plugin' plugins = [name] manager = PluginManager(Mock()) failed_plugins = manager.unload(plugins) assert failed_plugins == plugins assert manager.plugins == {}
def test_load_setup_too_many_arguments_fails(self): name = 'setup_too_many_arguments' plugins = [name] manager = PluginManager(Mock(), _plugin_module_import_prefix='fake_plugins') failed_plugins = manager.load(plugins) assert failed_plugins == plugins assert manager.plugins.keys() == []
class TestPluginManager(unittest.TestCase): """ Unit test for PluginManager """ def setUp(self): self.manager = PluginManager() self.manager.add_plugin_dir("/tmp/slog/share/slog/plugins") def testSearchPlugins(self): self.manager.scan_for_plugins() self.assertEqual(3, len(self.manager.get_available()))
def test_load_bad_callback_fails(self, mock): name = 'valid' plugins = [name] manager = PluginManager(Mock(), _plugin_module_import_prefix='fake_plugins') mock.side_effect = Exception() failed_plugins = manager.load(plugins) assert failed_plugins == plugins assert manager.plugins == {}
def test_load_ambiguous_config_fails(self, mock): name = 'valid' plugins = [name] manager = PluginManager(Mock(), _plugin_module_import_prefix='fake_plugins') mock.side_effect = AmbiguousConfigError() failed_plugins = manager.load(plugins) mock.assert_called_with(name) assert failed_plugins == plugins assert manager.plugins == {}
def test_unload_clean_close_succeeds(self): name = 'clean_close' plugins = [name] manager = PluginManager(Mock(), _plugin_module_import_prefix='fake_plugins') failed_plugins = manager.load(plugins) assert failed_plugins == [] assert manager.plugins.keys() == plugins failed_plugins = manager.unload(plugins) assert failed_plugins == [] assert manager.plugins.keys() == []
def run_admin(): """ Run PluginManager to administrate application. """ logging.basicConfig(format=CONFIG.get('logging'), level='INFO') source_path = os.path.dirname(__file__) PluginManager('admin', source_path=source_path).execute('configure')
def run_identica(): """ Run PluginManager to communicate with application identica bot. """ logging.basicConfig(format=CONFIG.get('logging'), level='INFO') PluginManager('identica', domain_url='http://192.168.44.150:5000').execute('run')
def __init__(self, **flask_args): cfgpath = os.path.join(self.get_root(), "config", "quail.json") # see if config exists if not os.path.exists(cfgpath): os.mkdir( os.path.dirname(cfgpath) ) with open( cfgpath, 'w' ) as f: f.write(DEFAULTCONFIG) # read in config with open( cfgpath, 'r' ) as f: self.config = loads( f.read() ) # add all api hooks self.add_api_hooks() # last plugin self.lastplugin = None # create plugin manager self.manager = PluginManager(self) self.manager.load_all() # create stack self.stack = [] # start listener thread thrd = listener.listenerThread(self, self.manager.plugins) thrd.setName("threadListener") thrd.daemon = True thrd.start() self.run(**flask_args)
def generate_document(self, template_id, field_data): """Return URL to the generated document - throw exception if not possible.""" # Check user system is allowed to use template. ts = TemplateServer(TEMPLATE_URL) """ templates = ts.get_templates(self._user_system_id) template_dict = {t[1]: t[2] for t in templates} do_pdf_dict = {t[1]: t[3] for t in templates} try: url = template_dict[template_id] do_pdf = do_pdf_dict[template_id] except KeyError: url = None raise RuntimeError( 'Template {0} not available for client.'.format( template_id) ) """ template = ts.get_template(self._user_system_id, template_id) if template is None: raise RuntimeError( "Template {0} not available for client.".format(template_id)) url = template[0] do_pdf = template[1] # Retrieve template from template server. real_url = TEMPLATE_BASE_URL + url file_base, extension = os.path.splitext(url) file_base = file_base.split('/').pop() tmp_name = '/tmp/{0}{1}'.format(template_id, extension) (fn, headers) = urllib.urlretrieve(real_url, tmp_name) # Finally generate document, store in appropriate place and # return URL. # Get plugin. plugin_mapping = PluginMapping.objects.filter( extension=extension.strip('.').upper())[0] plugin = PluginManager.get_plugin(plugin_mapping.plugin) # Get fields from template system fields = ts.get_template_fields(template_id) # Get output file name unique_url = get_unique_token() output_dir = os.path.join(settings.MEDIA_ROOT, 'files') extension = 'pdf' if do_pdf else plugin_mapping.output_type output_file = '.'.join([unique_url, extension]) output_path = os.path.join(output_dir, output_file) # TODO: Validate that fields in call exist in template, etc. output_url = settings.MEDIA_URL + 'files/' + output_file #raise RuntimeError("Not implemented: {0}".format(output_url)) plugin.generate_document(tmp_name, output_path, field_data, do_pdf) # Calculate SHA1 hash of output file sha1 = hashlib.sha1() with open(output_path, 'rb') as f: sha1.update(f.read()) hash = sha1.hexdigest() return (BROKER_BASE_URL + output_url, hash)
def test_unload_unregister_plugin_callbacks_error_succeeds(self, mock): name = 'clean_close' plugins = [name] manager = PluginManager(Mock(), _plugin_module_import_prefix='fake_plugins') failed_plugins = manager.load(plugins) assert failed_plugins == [] assert manager.plugins.keys() == plugins mock.side_effect = Exception() failed_plugins = manager.unload(plugins) assert failed_plugins == [] assert manager.plugins.keys() == [] mock.assert_called_with(name)
def test_01_Singleton(self): """ 1. Checking whether PluginManger class is singleton. """ self.pluginmanager.test_arg = 1 secondPluginManager = PluginManager() self.assertEqual(id(secondPluginManager), id(self.pluginmanager), 'Different IDs in references to PluginManager objects (not a singleton)') self.assertEqual(secondPluginManager.test_arg, 1, 'References point to different PluginManager objects (not a singleton')
def test_reload_unclean_close_succeeds(self): name = 'unclean_close' plugins = [name] cardinal = Mock(CardinalBot) cardinal.reloads = 0 manager = PluginManager(cardinal, _plugin_module_import_prefix='fake_plugins') failed_plugins = manager.load(plugins) assert failed_plugins == [] assert manager.plugins.keys() == plugins failed_plugins = manager.load(plugins) assert failed_plugins == [] assert manager.plugins.keys() == plugins assert cardinal.reloads == 1
def test_load_valid_list(self): name = 'valid' plugins = [name] manager = PluginManager(Mock(), _plugin_module_import_prefix='fake_plugins') failed_plugins = manager.load(plugins) assert failed_plugins == [] assert manager.plugins.keys() == plugins assert manager.plugins[name]['name'] == name assert inspect.ismodule(manager.plugins[name]['module']) assert isinstance(manager.plugins[name]['instance'], manager.plugins[name]['module'].TestValidPlugin) assert manager.plugins[name]['commands'] == [] assert manager.plugins[name]['callbacks'] == [] assert manager.plugins[name]['callback_ids'] == {} assert manager.plugins[name]['config'] is None assert manager.plugins[name]['blacklist'] == []
def generate_template_image(self, template_id, resolusion, image_type, file_name): """ Return a URL to the generated preview. """ # Check user system is allowed to use template. ts = TemplateServer(TEMPLATE_URL) templates = ts.get_templates(self._user_system_id) template_dict = {t[1]: t[2] for t in templates} do_pdf_dict = {t[1]: t[3] for t in templates} try: url = template_dict[template_id] do_pdf = do_pdf_dict[template_id] except KeyError: url = None raise RuntimeError( 'Template {0} not available for client.'.format(template_id)) # Retrieve template from template server. real_url = TEMPLATE_BASE_URL + url file_base, extension = os.path.splitext(url) file_base = file_base.split('/').pop() tmp_name = '/tmp/{0}{1}'.format(template_id, extension) (fn, headers) = urllib.urlretrieve(real_url, tmp_name) # Finally generate document, store in appropriate place and # return URL. # Get plugin. plugin_mapping = PluginMapping.objects.filter( extension=extension.strip('.').upper())[0] plugin = PluginManager.get_plugin(plugin_mapping.plugin) # Get fields from template system fields = ts.get_template_fields(template_id) # Get output file name unique_url = get_unique_token() output_dir = os.path.join(settings.MEDIA_ROOT, 'files') extension = ".png" output_file = file_name[:file_name.rfind('.')] + "_" + image_type output_file += extension output_path = os.path.join(output_dir, output_file) # TODO: Validate that fields in call exist in template, etc. output_url = settings.MEDIA_URL + 'files/' + output_file print "generate_template_image IS RUN" plugin.generate_template_image(tmp_name, output_path, resolusion, image_type, fields) # Calculate SHA1 hash of output file sha1 = hashlib.sha1() with open(output_path, 'rb') as f: sha1.update(f.read()) hash = sha1.hexdigest() return (BROKER_BASE_URL + output_url, hash)
def __init__(self, *args): super().__init__(*args) # Plugin support self.plugins = PluginManager(self) self.plugins.discover_plugins(enable_all=config.data['general']['enable_plugins']) # End plugin support # Updates self._toggled = False self._log_reader = None # Load Parsers self._load_parsers() self._settings = SettingsWindow() # Tray Icon self._system_tray = QSystemTrayIcon() self._system_tray.setIcon(QIcon(resource_path('data/ui/icon.png'))) self._system_tray.setToolTip("nParse") # self._system_tray.setContextMenu(self._create_menu()) self._system_tray.activated.connect(self._menu) self._system_tray.show() # Turn On self._toggle() if self.new_version_available(): self._system_tray.showMessage( "nParse Update".format(ONLINE_VERSION), "New version available!\ncurrent: {}\nonline: {}".format( CURRENT_VERSION, ONLINE_VERSION ), msecs=3000 ) self.plugins.hook(Plugin.on_app_start, self)
class PluginMapping(models.Model): """This class maps from file name extensions to document plugins. This means we use the extensions to specify the plugin. This also mean we don't allow these extensions to overlap, e.g. if one soite wishes to use them in a non-standard way. If this ever becomes a problem, the plugin spec should follow the document, not the extension.""" plugins = PluginManager.list_plugins() extension = models.CharField(_('Extension'), max_length=16, unique=True) output_type = models.CharField(_('Output Type'), max_length=16) plugin = models.CharField( _('Plugin'), max_length=255, choices=[(k, v.__doc__) for k, v in plugins.items()]) def __unicode__(self): return self.extension
def __init__(self, pcfg, clientsock, dsthost, dstport): """Open connection to dsthost:dstport, and return client and server proxies.""" logger.info("creating proxy from client to %s:%d" % (dsthost, dstport)) self.srv_proxy = None try: serversock = socket.create_connection((dsthost, dstport)) self.cli_proxy = MinecraftProxy(clientsock) except Exception as e: clientsock.close() logger.error("Couldn't connect to %s:%d - %s", dsthost, dstport, str(e)) logger.info(traceback.format_exc()) return self.srv_proxy = MinecraftProxy(serversock, self.cli_proxy) self.plugin_mgr = PluginManager(pcfg, self.cli_proxy, self.srv_proxy) self.cli_proxy.plugin_mgr = self.plugin_mgr self.srv_proxy.plugin_mgr = self.plugin_mgr
def handle(self, cli_sock, addr): logger.info('Incoming connection from %s' % repr(addr)) try: srv_sock = create_connection((self.target_host, self.target_port)) cli_proxy = MinecraftProxy(cli_sock) except Exception as e: cli_sock.close() logger.error("Couldn't connect to %s:%d - %s", self.target_host, self.target_port, str(e)) logger.info(traceback.format_exc()) return srv_proxy = MinecraftProxy(srv_sock, cli_proxy) plugin_mgr = PluginManager(pcfg, cli_proxy, srv_proxy) cli_proxy.plugin_mgr = plugin_mgr srv_proxy.plugin_mgr = plugin_mgr cli_proxy.start() srv_proxy.start()
def generate_fo_template(self, template_id, fo_file): """ Return a URL to the generated preview. """ # Check user system is allowed to use template. ts = TemplateServer(TEMPLATE_URL) templates = ts.get_templates(self._user_system_id) template_dict = {t[1]: t[2] for t in templates} do_pdf_dict = {t[1]: t[3] for t in templates} print "TEMPLATE_ID: " + template_id print "TEMPLATES: " + str(template_dict) try: url = template_dict[template_id] do_pdf = do_pdf_dict[template_id] except KeyError: url = None raise RuntimeError( 'Template {0} not available for client.'.format(template_id)) # Retrieve template from template server. real_url = TEMPLATE_BASE_URL + url file_base, extension = os.path.splitext(url) file_base = file_base.split('/').pop() tmp_name = '/tmp/{0}{1}'.format(template_id, extension) (fn, headers) = urllib.urlretrieve(real_url, tmp_name) # Get plugin. plugin_mapping = PluginMapping.objects.filter( extension=extension.strip('.').upper())[0] plugin = PluginManager.get_plugin(plugin_mapping.plugin) # Get output file name unique_url = get_unique_token() output_dir = os.path.join(settings.MEDIA_ROOT, 'files') extension = "fo" output_file = '.'.join([unique_url, extension]) output_path = os.path.join(output_dir, output_file) output_url = settings.MEDIA_URL + 'files/' + output_file plugin.generate_xsl_fo_ghost_document(tmp_name, output_path) # Calculate SHA1 hash of output file sha1 = hashlib.sha1() with open(output_path, 'rb') as f: sha1.update(f.read()) hash = sha1.hexdigest() return (BROKER_BASE_URL + output_url, hash)
import sys, os, plat, config from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QApplication from plugins import PluginManager from host import Host if plat.Supports.hotkeys: import hotkeys # For easier usage calculate the path relative to here. here = os.path.abspath(os.path.dirname(__file__)) app = QApplication(sys.argv) app.setQuitOnLastWindowClosed(False) # Add kill-switch for development testing if DEBUG and plat.Supports.hotkeys: hotkeys.default.registerCommand('kill', app.exit) hotkeys.default._bind('ctrl+shift+k', 'kill') #endif plugHost = Host() pm = PluginManager(plugHost) pm.load(os.path.join(here, 'plugins')) hotkeys.default.load() app.exec_() config.default.save()
#! /usr/bin/env python # -*- coding: utf-8 -*- from plugins import PluginManager # User command alias = "echo" command = { alias: "Usage: !echo message\nMake the bot mimic your message." } # Plugin Action class EchoPlugin(PluginManager.Load): def action(self, cmds, scrib, c): if cmds[0] == command and len(cmds) >= 1: phrase="" for x in xrange (1, len (cmds)): phrase = phrase + str(cmds[x]) + " " return phrase PluginManager.addPlugin( command, alias, EchoPlugin() )
# User Alias and Command sleep_alias = "sleep" sleep_command = { sleep_alias: "Usage: !sleep \nMake the bot stop talking." } # Plugin Action class SleepPlugin(PluginManager.Load): def action(self, cmds, scrib, c): scrib.barf('ACT', 'Sleep called.') if cmds[0] == sleep_cmd and len(cmds)==1: msg = "Going to sleep. Goodnight!" scrib.settings.muted = 1 else: msg = "Zzz..." return msg wake_alias = "wake" wake_command = { wake_alias: "Owner command. Usage: !wake\nAllow the bot to talk." } class WakePlugin(PluginManager.Load): def action(self, cmds, scrib, c): scrib.barf('ACT', 'Wake called.') if cmds[0] == wake_cmd and scrib.settings.muted == 1: scrib.settings.muted = 0 msg = "Whoohoo!" else: msg = "But I'm already awake..." return msg PluginManager.addPlugin( sleep_command, sleep_alias, SleepPlugin() ) PluginManager.addPlugin( wake_command, wake_alias, WakePlugin() )
def test_constructor_plugins_not_a_list_typeerror(self, plugins): with pytest.raises(TypeError): PluginManager(Mock(), plugins)
class Gallery: def __init__(self, config, root_path): self.config = config self.root_path = root_path self.source_image_path = os.path.join(root_path, "source_images") self.source_video_path = os.path.join(root_path, "source_videos") self.theme_name = config.get("gallery", "theme") self.themes_path = os.path.join(root_path, "themes") self.theme_path = os.path.join(self.themes_path, self.theme_name) if not os.path.exists(self.theme_path): raise Exception("theme '%s' not found " % self.theme_name) themeconfigpath = os.path.join(self.theme_path, "config.txt") if not os.path.exists(themeconfigpath): raise Exception("couldn't find theme config.txt") self.config.read(themeconfigpath) self.templates_path = os.path.join(self.theme_path, "templates") self.template_path = os.path.join(root_path, "templates") self.output_path = os.path.join(root_path, "output") self.small_size = self.config.get("gallery", "small_image_size").split(",") self.large_size = self.config.get("gallery", "large_image_size").split(",") self.video_size = self.config.get("gallery", "video_max_size").split(",") self.configure_templates() self.discover_plugins() def discover_plugins(self): self.plugin_manager = PluginManager() self.plugin_manager.discover_plugins( os.path.join(self.root_path, "plugins")) def configure_templates(self): self.tempEnv = Environment( loader=FileSystemLoader(self.templates_path)) def get_template(self, templateName): return self.tempEnv.get_template(templateName) def generate(self): images = self.discover_images() videos = self.process_videos() print videos images = self.generate_images(images) # plugin call point - pre page generation, with images as # arguments (to provide extra context for pages) extra_context = self.plugin_manager.prePageGeneration( self.config, self.source_image_path, self.source_video_path, images, videos) self.generate_pages(images, videos, extra_context) self.copy_static_content() def upload(self): # plugin call point, generation complete - upload self.plugin_manager.upload(self.config, self.output_path) # plugin call point, generation complete - notify self.plugin_manager.notify(self.config, self.output_path) def copy_static_content(self): static_path = os.path.join(self.theme_path, "static") static_output_path = os.path.join(self.output_path, "static") if os.path.exists(static_output_path): shutil.rmtree(static_output_path) shutil.copytree(static_path, static_output_path) def discover_images(self): images = [] for filename in os.listdir(self.source_image_path): if filename.lower().find(".jpg") != -1: image = MediaObject( source_path=os.path.join( self.source_image_path, filename), filename=filename, output_path=self.output_path) image.target_small_size = self.small_size image.target_large_size = self.large_size images.append(image) print "%s images found" % len(images) return images def process_videos(self): videos = [] vp = videoprocessing.VideoProcessor() for filename in os.listdir(self.source_video_path): video = MediaObject(type=MediaObject.TYPE_VIDEO, filename=filename, source_path=os.path.join( self.source_video_path, filename), output_path=self.output_path) videos.append(video) if video.transcoded: # copy already transcoded video target_path = os.path.join(self.output_path, video.filename) print "copying m4v video: %s" % video.source_path shutil.copy(video.source_path, target_path) else: # transcode the others target_filename = video.filename[ :video.filename.find(".")] + ".m4v" video.filename = target_filename target_path = os.path.join(self.output_path, target_filename) print "transcoding %s to %s" % (video.source_path, target_path) params = vp.getSizeAndDuration(video.source_path) vp.trancodeRawVideo( video.source_path, target_path, params, self.video_size) video.thumb_path = vp.getScreencap( video.source_path, self.output_path) video.thumb_filename = os.path.split(video.thumb_path)[1] # get dimensions and duration params = vp.getSizeAndDuration( os.path.join(self.output_path, video.filename)) video.width = params.get('width', None) video.height = params.get('height', None) video.hours = params.get('hours', None) video.minutes = params.get('minutes', None) video.seconds = params.get('seconds', None) video.title = filename return videos def generate_pages(self, images, videos, extra_context): try: themeMode = self.config.get("theme", "THEME_MODE") except ConfigParser.NoOptionError: themeMode = 'static' # merge video and photo records media = [] media.extend(videos) media.extend(images) for mediaobject in media: if mediaobject.type == MediaObject.TYPE_PHOTO: mediaobject.page = "view_photo_%s.html" % mediaobject.id elif mediaobject.type == MediaObject.TYPE_VIDEO: mediaobject.page = "view_video_%s.html" % mediaobject.id if themeMode == 'ajax': return self.generate_ajax_pages(media, extra_context) elif themeMode == 'static': return self.generate_plain_pages(media, extra_context) else: raise Exception("unknown mode in theme") def generate_ajax_pages(self, media, extra_context): page_context = { 'root_url': self.config.get("gallery", "ROOT_URL"), 'imagecount': len(media), 'media': media, 'gallerytitle': self.config.get("gallery", "title"), } page_context.update(extra_context) self.render_page("index.html", "index.html", page_context) # create video embed pages for mediaitem in media: if mediaitem.type == MediaObject.TYPE_VIDEO: local_page_context = { 'video': mediaitem, 'root_url': self.config.get("gallery", "ROOT_URL"), } self.render_page("embedvideo.html", "embed_%s.html" % mediaitem.filename, local_page_context) self.render_static_pages(page_context) def generate_plain_pages(self, media, extra_context): indexIsAlbumPage = self.config.getboolean( "theme", "INDEX_IS_ALBUM_PAGE") imagesPerPage = int(self.config.get("theme", "IMAGES_PER_PAGE")) # set up previous and next links for i in range(len(media)): prevlink = None nextlink = None if i > 0: prevlink = media[i - 1].page if i < (len(media) - 1): nextlink = media[i + 1].page media[i].next_link = nextlink media[i].prev_link = prevlink pages = int(math.ceil((len(media) / float(imagesPerPage)))) page_context = { 'root_url': self.config.get("gallery", "ROOT_URL"), 'images_per_page': imagesPerPage, 'pages': pages, 'imagecount': len(media), 'gallerytitle': self.config.get("gallery", "title"), } page_context.update(extra_context) pagelinks = [] for page in range(pages): if page == 0 and indexIsAlbumPage: pagelinks.append( {'title': (int(page) + 1), 'link': "index.html"}) else: pagelinks.append( {'title': (int(page) + 1), 'link': "page%s.html" % (int(page) + 1)}) page_context['pagelinks'] = pagelinks # generate album pages if indexIsAlbumPage: currPageName = "index.html" else: currPageName = "page1.html" for page in range(pages): pageno = page + 1 print "generating page %s" % pageno page_media = media[page * imagesPerPage:pageno * imagesPerPage] # set the owner page for the media items for mediaitem in page_media: mediaitem.home_page = currPageName page_context['media'] = page_media page_context['pageno'] = pageno prevlink = None if page > 0: prevlink = "page%s.html" % page nextlink = None if pageno < pages: nextlink = "page%s.html" % (int(pageno) + 1) page_context['prevlink'] = prevlink page_context['nextlink'] = nextlink self.render_page("albumpage.html", currPageName, page_context) currPageName = "page%s.html" % (pageno + 1) # generate image and video view pages for mediaitem in media: if mediaitem.type == MediaObject.TYPE_PHOTO: local_page_context = { 'img': mediaitem, 'root_url': self.config.get("gallery", "ROOT_URL"), } self.render_page( "viewimage.html", mediaitem.page, local_page_context) if mediaitem.type == MediaObject.TYPE_VIDEO: local_page_context = { 'video': mediaitem, 'root_url': self.config.get("gallery", "ROOT_URL"), } self.render_page( "viewvideo.html", mediaitem.page, local_page_context) self.render_static_pages(page_context) def render_static_pages(self, context): indexIsAlbumPage = self.config.getboolean( "theme", "INDEX_IS_ALBUM_PAGE") if not indexIsAlbumPage: self.render_page("index.html", "index.html", context) # render any other template not in the list of reserved names for template in self.tempEnv.list_templates(): if template not in RESERVED_TEMPLATES: print "rendering static page - %s" % template self.render_page(template, template, context) def render_page(self, templateName, outputName, context): page_template = self.get_template(templateName) html = page_template.render(context) outfile = open(os.path.join(self.output_path, outputName), "w") outfile.write(html) outfile.close() def generate_images(self, images): p = Pool() images = p.map(process_image, [[image] for image in images]) print images return images
def save(self, *args, **kwargs): fo_file_path = "" bs = BrokerServer(document_broker_settings.BROKER_URL) set_broker_server(bs) # Before save if self.file != self._old_file: self.version = self.version + 1 """ We check if template contains HTML input fields. """ file_contents = self.file.read() if not "#[HTML]" in file_contents: """ Couldn't make the commit keyword work on the save method. pre_save= super(Template, self).save(commit=False, *args, **kwargs) Except: save() got an unexpected keyword argument 'commit' This is a dirty way to find the next file: """ found = True i = 0 while found: """ We traverse the files with this name and set the fo output file to be the next one in the row. """ wo_ext = str(self.file.name) wo_ext = wo_ext[:str(self.file.name).rfind(".")] ext = str(self.file.name)[str(self.file.name).rfind("."):] if i == 0: file_name = "files/" file_name += wo_ext else: file_name += wo_ext file_name += "_" + str(i) try: the_file = os.path.join( settings.MEDIA_ROOT, file_name + ext ) with open(the_file, 'r') as f: file_name = "files/" found = True except Exception as e: fo_file_path = file_name + ".fo" found = False i += 1 self.precompiled_file = fo_file_path plugin_mappings = bs.get_plugin_mappings() # Actual save super(Template, self).save(*args, **kwargs) # After save - extract field if file changed. if self.file != self._old_file: # Get plugin name from mapping (_, extension) = os.path.splitext(self.file.path) extension = extension.strip('.').upper() db = DocumentBroker(document_broker_settings.BROKER_URL) plugin_mappings = db.get_plugin_mappings() plugin = PluginManager.get_plugin(plugin_mappings[extension]) fields = plugin.extract_document_fields(str(self.file.path)) existing_fields = Field.objects.filter(document=self) for name, content_type in fields: if name not in [f.name for f in existing_fields]: """ We set the default input type to be text. """ input_type = "TEXT" """ We check if the field take HTML input and declare the input type alike. """ if len(name) > 7: if name[:6] == "[HTML]": input_type = "HTML" self.precompiled_file = None Field.objects.create( name=name, type=input_type, content_type="string", document=self)
class NomnsParse(QApplication): """Application Control.""" def __init__(self, *args): super().__init__(*args) # Plugin support self.plugins = PluginManager(self) self.plugins.discover_plugins(enable_all=config.data['general']['enable_plugins']) # End plugin support # Updates self._toggled = False self._log_reader = None # Load Parsers self._load_parsers() self._settings = SettingsWindow() # Tray Icon self._system_tray = QSystemTrayIcon() self._system_tray.setIcon(QIcon(resource_path('data/ui/icon.png'))) self._system_tray.setToolTip("nParse") # self._system_tray.setContextMenu(self._create_menu()) self._system_tray.activated.connect(self._menu) self._system_tray.show() # Turn On self._toggle() if self.new_version_available(): self._system_tray.showMessage( "nParse Update".format(ONLINE_VERSION), "New version available!\ncurrent: {}\nonline: {}".format( CURRENT_VERSION, ONLINE_VERSION ), msecs=3000 ) self.plugins.hook(Plugin.on_app_start, self) def _load_parsers(self): self._parsers = [ parsers.Maps(), parsers.Spells() ] for parser in self._parsers: self.plugins.hook(Plugin.on_parser_load, parser) if parser.name in config.data.keys() and 'geometry' in config.data[parser.name].keys(): g = config.data[parser.name]['geometry'] parser.setGeometry(g[0], g[1], g[2], g[3]) if config.data[parser.name]['toggled']: parser.toggle() def _toggle(self): if not self._toggled: try: config.verify_paths() except ValueError as error: self._system_tray.showMessage( error.args[0], error.args[1], msecs=3000) else: self._log_reader = logreader.LogReader( config.data['general']['eq_log_dir']) self._log_reader.new_line.connect(self._parse) self._toggled = True else: if self._log_reader: self._log_reader.deleteLater() self._log_reader = None self._toggled = False def _parse(self, new_line): if new_line: timestamp, text, charname = new_line # (datetime, text) # don't send parse to non toggled items, except maps. always parse maps for parser in [parser for parser in self._parsers if config.data[parser.name]['toggled'] or parser.name == 'maps']: parser.parse(timestamp, text, charname) def _menu(self, event): """Returns a new QMenu for system tray.""" menu = QMenu() menu.setAttribute(Qt.WA_DeleteOnClose) # check online for new version new_version_text = "" if self.new_version_available(): new_version_text = "Update Available {}".format(ONLINE_VERSION) else: new_version_text = "Version {}".format(CURRENT_VERSION) check_version_action = menu.addAction(new_version_text) menu.addSeparator() get_eq_dir_action = menu.addAction('Select EQ Logs Directory') menu.addSeparator() parser_toggles = set() for parser in self._parsers: toggle = menu.addAction(parser.name.title()) toggle.setCheckable(True) toggle.setChecked(config.data[parser.name]['toggled']) parser_toggles.add(toggle) menu.addSeparator() settings_action = menu.addAction('Settings') # Plugin support for adding menu items if self.plugins.has_plugins(): menu.addSeparator() plugin_options = self.plugins.prepare_plugin_menu(menu) self.plugins.hook(Plugin.on_menu_display, menu) # End plugin support menu.addSeparator() quit_action = menu.addAction('Quit') # Show the menu action = menu.exec_(QCursor.pos()) # Plugin support for handling menu actions if plugin_options: plugin_options(action) self.plugins.hook(Plugin.on_menu_click, action) # End plugin support if action == check_version_action: webbrowser.open('https://github.com/nomns/nparse/releases') elif action == get_eq_dir_action: dir_path = str(QFileDialog.getExistingDirectory( None, 'Select Everquest Logs Directory')) if dir_path: config.data['general']['eq_log_dir'] = dir_path config.save() self._toggle() elif action == settings_action: if self._settings.exec_(): # Update required settings for parser in self._parsers: if parser.windowOpacity() != config.data['general']['parser_opacity']: parser.setWindowOpacity( config.data['general']['parser_opacity'] / 100) parser.settings_updated() # some settings are saved within other settings automatically # force update for parser in self._parsers: if parser.name == "spells": parser.load_custom_timers() elif action == quit_action: if self._toggled: self._toggle() # save parser geometry for parser in self._parsers: g = parser.geometry() config.data[parser.name]['geometry'] = [ g.x(), g.y(), g.width(), g.height() ] config.save() self._system_tray.setVisible(False) # Plugin support self.plugins.hook(Plugin.on_app_quit, self) self.quit() elif action in parser_toggles: parser = [ parser for parser in self._parsers if parser.name == action.text().lower()][0] parser.toggle() def new_version_available(self): # this will only work if numbers go up try: for (o, c) in zip(ONLINE_VERSION.split('.'), CURRENT_VERSION.split('.')): if int(o) > int(c): return True except: return False
myComm.__name__ = name return myComm # 1 from discord.ext import commands log = logging.getLogger("Rotating Log") load_dotenv() TOKEN = os.getenv('DISCORD_TOKEN') passwd = os.getenv('passwd') dbname = os.getenv('dbname') username = os.getenv('username') prefix = os.getenv('prefix') dbconn = DataBase(dbname, username, passwd) pg = PluginManager(log, dbconn, prefix) commander = pg.get_plugins() # 2 bot = commands.Bot(command_prefix='!') for (kw, comm) in commander.items(): botcomms = bindfunction(kw, comm) myhelp = getattr(comm, "myhelp", "No help provided") bot.add_command(commands.Command(botcomms, name=kw, help=myhelp)) @bot.event async def on_ready(): #print(f'{bot.user.name} has connected to Discord!') pass
#! /usr/bin/env python # -*- coding: utf-8 -*- from plugins import PluginManager # User command alias = "control" command = { alias: "Usage: !control password\nAllow user to have access to bot commands." } # Plugin Action class ControlPlugin(PluginManager.Load): def action(self, cmds, scrib, c): if cmds[0] == command and len(cmds) > 1 and scrib.source not in scrib.owners: msg = "" if cmds[1] == scrib.settings.password: scrib.owners.append(scrib.source) msg = "You've been added to controllers list." else: msg = "Try again." return msg PluginManager.addPlugin( command, alias, ControlPlugin() )
def setUp(self): self.pluginmanager = PluginManager()
def setUp(self): self.manager = PluginManager() self.manager.add_plugin_dir("/tmp/slog/share/slog/plugins")
#! /usr/bin/env python # -*- coding: utf-8 -*- from plugins import PluginManager import os # User command alias = "fortune" command = { alias: "See your fortune." } # Plugin Action class FortunePlugin(PluginManager.Load): def action(self, cmds, scrib, c): if scrib.scrib.settings.debug == 1: PluginManager.barf(PluginManager.DBG, "Fortune Plugin activated.") if cmds[0] == command and len(cmds) >= 1: msg = "".join([i for i in os.popen('fortune').readlines()]).replace('\n\n','\n').replace('\n', ' ') msg = self.filter(msg) PluginManager.addPlugin( command, alias, FortunePlugin() )
def discover_plugins(self): self.plugin_manager = PluginManager() self.plugin_manager.discover_plugins( os.path.join(self.root_path, "plugins"))
def action(self, cmds, scrib, c): if scrib.scrib.settings.debug == 1: PluginManager.barf(PluginManager.DBG, "Fortune Plugin activated.") if cmds[0] == command and len(cmds) >= 1: msg = "".join([i for i in os.popen('fortune').readlines()]).replace('\n\n','\n').replace('\n', ' ') msg = self.filter(msg)
class App(object): """ This class is the main app class, which starts Quail """ flask = Flask(__name__) """ Contains the main flask instance """ # quail version VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH = 1, 6, 'B' def __init__(self, **flask_args): cfgpath = os.path.join(self.get_root(), "config", "quail.json") # see if config exists if not os.path.exists(cfgpath): os.mkdir( os.path.dirname(cfgpath) ) with open( cfgpath, 'w' ) as f: f.write(DEFAULTCONFIG) # read in config with open( cfgpath, 'r' ) as f: self.config = loads( f.read() ) # add all api hooks self.add_api_hooks() # last plugin self.lastplugin = None # create plugin manager self.manager = PluginManager(self) self.manager.load_all() # create stack self.stack = [] # start listener thread thrd = listener.listenerThread(self, self.manager.plugins) thrd.setName("threadListener") thrd.daemon = True thrd.start() self.run(**flask_args) def do_query(self, query="", plugin_name=None, n=0): """ Perform a query. Can be called by flask or another process """ # get information about the user n = n or request.args.get("n") or 0 self.user_type = request.args.get("type") or "human" # are we autorized? response = None if len(query): # check the last used plugin first if self.lastplugin: response = self.run_plugin(self.lastplugin, query) # locate correct plugin if not response: for plugin in self.manager.plugins: response = self.run_plugin(plugin, query) if response: break # if there is no response, try and parse something from wolfram alpha if not response: response = wolfram.parse(query, self.config["wa-api-key"]) # still no response: error if not response: response = Packet() response["status"] = STATUS_NO_HIT # add the response to the stack out = response.format() self.stack.append(out) # n is the amount of packets to return if n == 0: # return all of them out = self.stack self.stack = [] else: # return 'n' packets out = self.stack[-n:] self.stack = self.stack[:-n] # return the response return Response(dumps(out), mimetype='application/json') def run_plugin(self, plugin, query): """ Run a plugin if it can accept the query """ # set new query, and validate plugin["instance"].new_query(query) if plugin["instance"].validate(): # add to history, if human-made if "human" in self.user_type: self.lastplugin = plugin # parse the query plugin["instance"].parse() return plugin["instance"].resp return None def upload_resource(self, secret): """ Upload a resource to quail so it can be parsed/used in a query """ response = Packet() if request.method == 'POST': file = request.files['file'] filename = secure_filename(file.filename) if fileg: file.save(os.path.join(self.config["upload-folder"], filename)) response["status"] = STATUS_OK response["text"] = filename return Response(dumps( response.format() ), mimetype='application/json') def web_gui(self, secret, plugin=None, path="/"): """ Web interface for quail interaction """ html = "" root = "" # quail's site if not plugin: if request.args.has_key("query"): text = request.args.get("query") q = loads(self.do_query(self.config["secret"], query=text, n=1).data) html = render_template( os.path.join(root, "old/query.html"), query=q ) elif path == "/": t = "" for plugin in self.manager.plugins: html = plugin["instance"].html_provider() if html: t += "<div class=\"plugin\"><div class=\"title\">%s</div><div class=\"data\">%s</div></div>" % (plugin["instance"].__class__.__name__, html) html = render_template( os.path.join(root, "old/index.html"), body=t) return html def calendar(self, month=0, year=0): """ Web interface for quail interaction """ root = "" # format events to be displayed out = [] now = datetime.datetime.today() # find year if year: now = now.replace(year=int(year)) # find months if month: now = now.replace(month=int(month)) # get previous month one_day = datetime.timedelta(days=1) last_month = now - one_day while last_month.month == now.month or last_month.day > now.day: last_month -= one_day try: days_in_month = (datetime.date(now.year, now.month+1, 1) - datetime.date(now.year, now.month, 1)).days except ValueError: days_in_month = 31 # must be december try: day_in_last_month = (datetime.date(last_month.year, last_month.month+1, 1) - datetime.date(last_month.year, last_month.month, 1)).days except ValueError: day_in_last_month = 31 # must be december # all days into a list for i in xrange(0, days_in_month+1): events_for_day = self.calender.events.year(now.year).month(now.month).day(i+1) today = {"day": i+1, "events": events_for_day, "month": "in"} out.append(today) # prepend previous month days for i in xrange( 0, int(datetime.date(now.year, now.month, 1).strftime('%w')) ): events_for_day = self.calender.events.year(now.year).month(now.month-1).day(i+1) today = {"day": day_in_last_month-i, "events": events_for_day, "month": "out"} out.insert(0, today) # split the output into weeks weeksout = [] week_ct = -1; for i in xrange(0, days_in_month+i+1): if i%7 == 0: week_ct += 1 weeksout.append([]) try: weeksout[week_ct].append(out[i]) except IndexError: pass # render output return render_template( os.path.join(root, "cal.html"), events=weeksout, title=now.strftime("%B %Y"),now=now) def web(self): """ Web interface for quail interaction """ root = "" # first time? if not self.config.has_key("welcome") or (self.config.has_key("welcome") and not self.config["welcome"]): return render_template( os.path.join(root, "welcome.html")) else: return render_template( os.path.join(root, "index.html")) def updatequaildotjson(self): """ Update config/quail.json file """ cfgpath = os.path.join(self.get_root(), "config", "quail.json") if request.args.get("data") and self.config["welcome"] == False: with open( cfgpath, 'w' ) as f: try: data = loads( request.args.get("data") ) data["welcome"] = True self.config["welcome"] = True f.write( dumps(data) ) except TypeError: f.write( dumps(self.config) ) return "BAD" return "OK" return "NO DATA OR PERMISSION DENIED" def web_query(self): q = self.do_query( request.args.get('q') ) return render_template( "query.html", query=loads(q.data) ) def run(self, **flask_args): """ Sets all the flask options behind the scenes, and starte Flask """ # multiple rules for a query self.flask.add_url_rule("/v2/<secret>/query", "query", view_func=self.do_query) self.flask.add_url_rule("/v2/<secret>/query/<query>", "query", view_func=self.do_query) self.flask.add_url_rule("/v2/<secret>/query/<query>/<int:n>", "query", view_func=self.do_query) self.flask.add_url_rule("/v2/<secret>/query/<query>/use/<plugin_name>", "query", view_func=self.do_query) self.flask.add_url_rule("/v2/<secret>/query/<query>/use/<plugin_name>/<int:n>", "query", view_func=self.do_query) # uploading of files self.flask.add_url_rule("/v2/<secret>/upload", "upload", methods=["POST"], view_func=self.upload_resource) # web interface self.flask.add_url_rule("/v2/<secret>/web", "web", view_func=self.web_gui) self.flask.add_url_rule("/v2/<secret>/web/<path>", "web", view_func=self.web_gui) self.flask.add_url_rule("/v2/<secret>/<plugin>/web", "web", view_func=self.web_gui) self.flask.add_url_rule("/v2/<secret>/<plugin>/web/<path>", "web", view_func=self.web_gui) # web interface self.flask.add_url_rule("/", "newweb", view_func=self.web) self.flask.add_url_rule("/cal", "web_cal", view_func=self.calendar) self.flask.add_url_rule("/cal/<int:month>", "web_cal", view_func=self.calendar) self.flask.add_url_rule("/cal/<int:month>/<int:year>", "web_cal", view_func=self.calendar) self.flask.add_url_rule("/search", "query_search", view_func=self.web_query) self.flask.add_url_rule("/quail.json", "updatequaildotjson", view_func=self.updatequaildotjson) # run flask self.flask.run(host=self.config["host"], port=self.config["port"], **flask_args) def get_root(self): """ Get root Quail directory """ return os.path.dirname( os.path.dirname( os.path.abspath(__file__) ) ) def add_api_hooks(self): """ Add api hooks for plugins to access later on, like people, events, etc """ self.calender = Calender(self) self.files = UserFiles(self) self.people = PeopleContainer(self)
def test_load_plugins_not_a_list_or_string_typeerror(self, plugins): manager = PluginManager(Mock()) with pytest.raises(TypeError): manager.load(plugins)