From 3c01d763918dc1867139f6255d8892530f00cf14 Mon Sep 17 00:00:00 2001 From: Federico Luzzi Date: Tue, 2 Jul 2024 16:53:07 -0300 Subject: [PATCH] add contexts and api plugins --- connpy/_version.py | 2 +- connpy/api.py | 2 + connpy/connapp.py | 3 +- connpy/core_plugins/context.py | 154 +++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 connpy/core_plugins/context.py diff --git a/connpy/_version.py b/connpy/_version.py index 87eb503..0112fa2 100644 --- a/connpy/_version.py +++ b/connpy/_version.py @@ -1,2 +1,2 @@ -__version__ = "4.1.0b1" +__version__ = "4.1.0b2" diff --git a/connpy/api.py b/connpy/api.py index 9ae7928..99f10c8 100755 --- a/connpy/api.py +++ b/connpy/api.py @@ -1,4 +1,5 @@ from flask import Flask, request, jsonify +from flask_cors import CORS from connpy import configfile, node, nodes, hooks from connpy.ai import ai as myai from waitress import serve @@ -6,6 +7,7 @@ import os import signal app = Flask(__name__) +CORS(app) conf = configfile() PID_FILE1 = "/run/connpy.pid" diff --git a/connpy/connapp.py b/connpy/connapp.py index 049fbb4..2c9c497 100755 --- a/connpy/connapp.py +++ b/connpy/connapp.py @@ -8,7 +8,7 @@ import sys import inquirer from .core import node,nodes from ._version import __version__ -from .api import start_api,stop_api,debug_api +from .api import start_api,stop_api,debug_api,app from .ai import ai from .plugins import Plugins import yaml @@ -42,6 +42,7 @@ class connapp: the config file. ''' + self.app = app self.node = node self.nodes = nodes self.start_api = start_api diff --git a/connpy/core_plugins/context.py b/connpy/core_plugins/context.py new file mode 100644 index 0000000..6922abf --- /dev/null +++ b/connpy/core_plugins/context.py @@ -0,0 +1,154 @@ +import argparse +import yaml +import re + + +class context_manager: + + def __init__(self, connapp): + self.connapp = connapp + self.config = connapp.config + self.contexts = self.config.config["contexts"] + self.current_context = self.config.config["current_context"] + self.regex = [re.compile(regex) for regex in self.contexts[self.current_context]] + + def add_context(self, context, regex): + if not context.isalnum(): + print("Context name has to be alphanumeric.") + exit(1) + elif context in self.contexts: + print(f"Context {context} already exists.") + exit(2) + else: + self.contexts[context] = regex + self.connapp._change_settings("contexts", self.contexts) + + def modify_context(self, context, regex): + if context == "all": + print("Can't modify default context: all") + exit(3) + elif context not in self.contexts: + print(f"Context {context} doesn't exist.") + exit(4) + else: + self.contexts[context] = regex + self.connapp._change_settings("contexts", self.contexts) + + def delete_context(self, context): + if context == "all": + print("Can't delete default context: all") + exit(3) + elif context not in self.contexts: + print(f"Context {context} doesn't exist.") + exit(4) + else: + self.contexts.pop(context) + self.connapp._change_settings("contexts", self.contexts) + + def list_contexts(self): + for key in self.contexts.keys(): + if key == self.current_context: + print(f"{key} * (active)") + else: + print(key) + + def set_context(self, context): + if context not in self.contexts: + print(f"Context {context} doesn't exist.") + exit(4) + elif context == self.current_context: + print(f"Context {context} already set") + exit(0) + else: + self.connapp._change_settings("current_context", context) + + def show_context(self, context): + if context not in self.contexts: + print(f"Context {context} doesn't exist.") + exit(4) + else: + yaml_output = yaml.dump(self.contexts[context], sort_keys=False, default_flow_style=False) + print(yaml_output) + + + @staticmethod + def add_default_context(config): + config_modified = False + if "contexts" not in config.config: + config.config["contexts"] = {} + config.config["contexts"]["all"] = [".*"] + config_modified = True + if "current_context" not in config.config: + config.config["current_context"] = "all" + config_modified = True + if config_modified: + config._saveconfig(config.file) + + def match_any_regex(self, node, regex_list): + return any(regex.match(node) for regex in regex_list) + + def modify_node_list(self, *args, **kwargs): + filtered_nodes = [node for node in kwargs["result"] if self.match_any_regex(node, self.regex)] + return filtered_nodes + + def modify_node_dict(self, *args, **kwargs): + filtered_nodes = {key: value for key, value in kwargs["result"].items() if self.match_any_regex(key, self.regex)} + return filtered_nodes + +class Preload: + def __init__(self, connapp): + #define contexts if doesn't exist + connapp.config.modify(context_manager.add_default_context) + #filter nodes using context + cm = context_manager(connapp) + connapp.nodes_list = [node for node in connapp.nodes_list if cm.match_any_regex(node, cm.regex)] + connapp.folders = [node for node in connapp.folders if cm.match_any_regex(node, cm.regex)] + connapp.config._getallnodes.register_post_hook(cm.modify_node_list) + connapp.config._getallfolders.register_post_hook(cm.modify_node_list) + connapp.config._getallnodesfull.register_post_hook(cm.modify_node_dict) + +class Parser: + def __init__(self): + self.parser = argparse.ArgumentParser(description="Manage contexts with regex matching", formatter_class=argparse.RawTextHelpFormatter) + self.description = "Manage contexts with regex matching" + + # Define the context name as a positional argument + self.parser.add_argument("context_name", help="Name of the context", nargs='?') + + group = self.parser.add_mutually_exclusive_group(required=True) + group.add_argument("-a", "--add", nargs='+', help='Add a new context with regex values. Usage: context -a name "regex1" "regex2"') + group.add_argument("-r", "--rm", "--del", action='store_true', help="Delete a context. Usage: context -d name") + group.add_argument("--ls", action='store_true', help="List all contexts. Usage: context --list") + group.add_argument("--set", action='store_true', help="Set the used context. Usage: context --set name") + group.add_argument("-s", "--show", action='store_true', help="Show the defined regex of a context. Usage: context --show name") + group.add_argument("-e", "--edit", "--mod", nargs='+', help='Modify an existing context. Usage: context --mod name "regex1" "regex2"') + +class Entrypoint: + def __init__(self, args, parser, connapp): + if args.add and len(args.add) < 2: + parser.error("--add requires at least 2 arguments: name and at least one regex") + if args.edit and len(args.edit) < 2: + parser.error("--edit requires at least 2 arguments: name and at least one regex") + if args.ls and args.context_name is not None: + parser.error("--ls does not require a context name") + if args.rm and not args.context_name: + parser.error("--rm require a context name") + if args.set and not args.context_name: + parser.error("--set require a context name") + if args.show and not args.context_name: + parser.error("--show require a context name") + + cm = context_manager(connapp) + + if args.add: + cm.add_context(args.add[0], args.add[1:]) + elif args.rm: + cm.delete_context(args.context_name) + elif args.ls: + cm.list_contexts() + elif args.edit: + cm.modify_context(args.edit[0], args.edit[1:]) + elif args.set: + cm.set_context(args.context_name) + elif args.show: + cm.show_context(args.context_name)