Pyspeed: an asynchronous CLI tool made to speed up python by avoiding running the script running more than once using sockets and/or files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio, socket, os | |
from watchdog.events import FileSystemEventHandler | |
from watchdog.observers import Observer | |
from watchdog.observers.polling import PollingObserver | |
from multiprocessing import Process | |
class socket_handler: | |
async def run_server(self, address, port, printrun, handle): | |
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
self.server = server | |
server.bind((address, port)) | |
server.listen(8) | |
if printrun: | |
print("Running!") | |
server.setblocking(False) | |
loop = asyncio.get_event_loop() | |
while True: | |
client, _ = await loop.sock_accept(server) | |
loop.create_task(handle(client)) | |
async def handle_client(self, client): | |
loop = asyncio.get_event_loop() | |
request = None | |
try: | |
while True: | |
request = (await loop.sock_recv(client, 255)).decode('utf8') | |
response = self.handle_request(client, *([''] + str(request).replace('\n', '').split(' '))) + '\n' | |
await loop.sock_sendall(client, response.encode('utf8')) | |
client.close() | |
except (BrokenPipeError, ConnectionAbortedError): | |
pass | |
def handle_request(self, client, *argv): | |
return ''.join(argv) | |
def run(self, address="localhost", port=50200, printrun=False): | |
asyncio.run(self.run_server(address, port, printrun, self.handle_client)) | |
class file_handler(FileSystemEventHandler): | |
def __init__(self, handle_path=''): | |
self.observer = Observer() | |
self.handle_path = handle_path | |
self.modified = False | |
if isinstance(self.observer, PollingObserver): | |
raise TypeError("Cannot use polling observer") | |
def run(self, handle_path=None, printrun=False): | |
if not handle_path: | |
handle_path = self.handle_path | |
self.handle_path = handle_path | |
self.observer.schedule(self, path=handle_path, recursive=False) | |
self.observer.start() | |
if printrun: | |
print("Running!") | |
try: | |
while True: | |
pass | |
except KeyboardInterrupt: | |
self.observer.stop() | |
self.observer.join() | |
def clear_handle(self): | |
with open(self.handle_path, "w+") as file: | |
self.modified = True | |
file.write('') | |
return True | |
def generate_handle(self, program_name, handle_path=None): | |
if not handle_path: | |
handle_path = self.handle_path | |
with open(os.path.join(handle_path, program_name), 'r+') as handlefile: | |
self.handle_path = os.path.join(handle_path, program_name) | |
return handlefile | |
def on_modified(self, event): | |
if os.path.isdir(event.src_path): return | |
if not self.modified: | |
with open(event.src_path, 'r+') as file: | |
lines = file.readlines().copy() | |
file.seek(0) | |
for x in lines: | |
file.write(self.handle_data(file, *([''] + x.replace('\n', '').split(' ')))) | |
self.modified = True | |
else: | |
self.modified = False | |
def handle_data(self, file, *argv): | |
return ''.join(argv) | |
class pyspeed_handler(file_handler, socket_handler): | |
def run(self, address="localhost", port=50200, handle_path=None, printrun=False): | |
socketproc = Process(target=socket_handler.run, args=(self, address, port, printrun)) | |
fileproc = Process(target=file_handler.run, args=(self, handle_path, printrun)) | |
socketproc.start() | |
fileproc.start() | |
try: | |
while True: | |
pass | |
except KeyboardInterrupt: | |
socketproc.terminate() | |
fileproc.terminate() | |
socketproc.join() | |
fileproc.join() | |
def handle_request(self, client, *argv): | |
return self.handle_all(self, client, *argv) | |
def handle_data(self, file, *argv): | |
return self.handle_all(self, file, *argv) | |
def handle_all(self, ctx, *argv): | |
return ''.join(argv) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Docs
Usage
Socket handler usage
The socket handler opens a local socket to send data to the script. to parse data, override the
handle_request
method. the return value will be sent back to the client. all handlers will take a source object and all the data split up by spaces in*argv
. for the socket object, the source is the client object.argv[0]
is a blank string. to run the server, call the run method with the address and port parametersTo send input to the script, run the script in the background then use this function
however you need to know how long it will take for the code to run
Windows (requires cygwin tools timeout and nc):
Linux/MacOS:
File handler usage
The file handler watches a file for changes and sends any written data to the
handle_data
method. the return value will be written to the file and the source object is a file object of the handle file. theargv
parameter has the same rules as the socket handler. to run the listener, call the run method with thehandle_file
parameterThis class requires watchdog dependency
you still need to know the timing of the code for input/output
Windows:
Linux/MacOS:
Combined handler
The combined handler opens a socket and listens for modifications on a file. it sends socket data to
handle_request
, file data tohandle_data
and both tohandle_all
. the source object forhandle_request
will be a client object, a file object forhandle_data
and either forhandle_all
. the return value will be either sent back to the socket or written to the file depending on the method. to run the server, call the run method and pass the address, port and handle_path which will be passed to the handlers.Runs both handlers, so any of the above I/O commands will work
API reference
TODO