python - How should multiple parsers for keywords in strings be structured? -
i'm writing code parses strings, using simple keywords. on parsing, code performs various actions, such printing response, running functions etc. , keeps track of whether able respond.
i using multiple parsers , have illustrated in code shown below.
what better ways structure code, particularly mind scalability , code compactness? example, imagine many more parsers being added operate on principles more complex simple keyword-spotting.
mwe:
#!/usr/bin/python import json import os import requests import subprocess import sys def main(): message = "how you" #message = "ip address" #message = "restart" triggered = [ parse_1(message = message), parse_2(message = message) ] if not any(triggered): report_help() def parse_1( message = none ): def keyphrases_text_response( message = none, keyphrases = none, response = none ): if any(pattern in message pattern in keyphrases): print(response) return true else: return false triggered = [ keyphrases_text_response( message = message, keyphrases = [ "image" ], response = "http://i.imgur.com/miqrlth.jpg" ), keyphrases_text_response( message = message, keyphrases = [ "sup", "hi" ], response = "sup home bean" ), keyphrases_text_response( message = message, keyphrases = [ "how you", "are well", "status" ], response = "nae bad fam" ), keyphrases_text_response( message = message, keyphrases = [ "help", "what can do" ], response = "i can report ip address , can restart script." ) ] if any(triggered): return true else: return false def parse_2( message = none ): triggered = [] if any(pattern in message pattern in\ [ "ip", "i.p.", "ip address", "i.p. address", "ip address" ] ): triggered.append(true) report_ip() if any(pattern in message pattern in\ [ "restart" ] ): triggered.append(true) restart() if any(pattern in message pattern in\ [ "ssh", "reverse" ] ): triggered.append(true) engage_command( command = "ssh -r 10000:localhost:22 www.sern.ch", background = true ) if any(triggered): return true else: return false def report_ip( contact = none, country = true ): ip = "unknown" try: data_ip_website = requests.get("http://ipinfo.io/json") data_ip = data_ip_website.json() ip = data_ip["ip"] country = data_ip["country"] except: pass text = "ip address: " + ip if country: text = text + " (" + country + ")" print(text) def restart(): print("restart! (and i'm in crazy loop!)") import __main__ os.execv(__main__.__file__, sys.argv) def report_help(): print("i can report ip address, can restart script , can run commands.") def engage_command( command = none, background = false ): print("engage command: {command}".format(command = command)) if not background: process = subprocess.popen( [command], shell = true, executable = "/bin/bash" ) process.wait() output, errors = process.communicate() return output else: subprocess.popen( [command], shell = true, executable = "/bin/bash" ) return none if __name__ == "__main__": main()
note: code below python 3.5 or higher.
first, separate logic of parsers logic of code runs strings through parsers. let's start code latter:
from typing import list def run_parsers(message: str, parsers: list[baseparser]) -> none: parser in parsers: parser.parse_message(message)
note: in latest python versions, can annotate code. reason why chose here make clear function doesn't care "type" of parser gets. expects list of baseparser
instances(including instances of classes inherit baseparser
) , calls parse_sting
method of each of them on message
. function doesn't care parse_message
does.
next, want define api parser objects run_parsers
can use them without knowing how work.
class baseparser: def __init__(self): self.triggered = false def parse_message(self, message: str): raise notimplementederror
as can see baseparser
has no logic, says whoever inherits me should define parse_message
. also, inheriters triggered
attribute.
now, let's see code 1 such inheriter.
class imageparser: def __init__(self): super().__init__() self.key_phrases = ('jpg', 'png') def parse_message(self, message): phrase in self.key_phrases: if phrase in message: self.respond() self.triggered = true def respond(self): do_something_here()
as long inheriters follow "rules" set baseinheriter(i.e. implement method , have attribute called triggered
), run_parsers
happily run them.
note:imageparser
sets triggered
true , how can determine parsers took action.
finally, let's convert main
function make work above code:
def main(): message = 'how you?' parsers = [imageparser(), ipparser()] run_parsers(message, parsers) if not any([parser.triggered parser in parsers]): show_help()
important tip: make sure read , use pep8 guidelines. object-oriented design complicates flow of application , don't want further complicate things coming own code style or conventions.
Comments
Post a Comment