| import sys | |
| import os | |
| from multiprocessing import Pool, cpu_count, Process | |
| import json | |
| def _except_hook(cls, exception, traceback): | |
| ''' | |
| Function used by :py:func:`pqt5_exception_workaround`. Don't call this directly. | |
| ''' | |
| sys.__excepthook__(cls, exception, traceback) | |
| def pqt5_exception_workaround(): | |
| ''' | |
| Workaround to prevent pyqt5 from silently eating exceptions. | |
| Call this at the beginning of your progame and you will experience relieve. | |
| ''' | |
| sys.excepthook = _except_hook | |
| class Persival(): | |
| ''' | |
| Keeps values persistent between program runs. | |
| ''' | |
| def __init__(self, persival_file='persival.json'): | |
| ''' | |
| Will try to load parameters from the persival_file. | |
| If the file does not exists this will be silently ignored and the file will be created when :py:meth:`save` will be called. | |
| ''' | |
| self.persival_file=persival_file | |
| if os.path.exists(persival_file): | |
| with open(self.persival_file, 'r') as file: | |
| self.data=json.load(file) | |
| else: | |
| self.data={} | |
| def setDefault(self, name, value): | |
| ''' | |
| Sets the given value only if no information was present in the persival file or if the persival file was not found. | |
| ''' | |
| if not name in self.data.keys(): | |
| self.data[name]=value | |
| def get(self, name): | |
| ''' | |
| Returns the saved value for the given parameter. | |
| ''' | |
| return self.data[name] | |
| def set(self, name, value): | |
| ''' | |
| Store the given value in memory. You have to call save to dump the value to the disk. | |
| ''' | |
| self.data[name] = value | |
| # print('Break') | |
| def save(self): | |
| ''' | |
| Saves the content to a file. | |
| ''' | |
| with open(self.persival_file, 'w') as file: | |
| json.dump(self.data, file) | |
| class ProcessingHelper(): | |
| ''' | |
| Helper working around the limitations of Pool. | |
| ''' | |
| def __init__(self, parallel=False, maxCpu=None): | |
| self.funcs=[] | |
| self.parallel=parallel | |
| self.maxCpu=maxCpu | |
| self.retval=[] | |
| def add(self, function, args, kwargs={}): | |
| ''' | |
| Add a function to the processing pool. | |
| :param function: function to be executed | |
| :param args: list. Provice the positional arguments | |
| :param kwargs: dict. Optional, provide the kwargs | |
| ''' | |
| if self.parallel: | |
| self.funcs.append({'func': function, 'args': args, 'kwargs': kwargs}) | |
| else: | |
| retval=function(*args, **kwargs) | |
| self.retval.append(retval) | |
| def run(self): | |
| ''' | |
| Start processing. | |
| :returns: list of results. The orgdering matches the sequence of add calls. | |
| ''' | |
| processes=cpu_count() | |
| if not self.maxCpu is None: | |
| processes=min(self.maxCpu, processes) | |
| # Windows does not handle full cpu loads well, so leave one CPU unutilized for Windows. | |
| if os.name == 'nt': | |
| processes -=1 | |
| if self.parallel: | |
| with Pool(processes=processes) as pool: | |
| result=pool.map(self._myrun, range(len(self.funcs))) | |
| else: | |
| result=self.retval | |
| return result | |
| def _myrun(self, paramNo): | |
| ''' | |
| wrapper around the function for pool | |
| :param paramNo: | |
| ''' | |
| param=self.funcs[paramNo] | |
| func=param['func'] | |
| args= param['args'] | |
| kwargs= param['kwargs'] | |
| retval=func(*args, **kwargs) | |
| return retval | |