def run_fit(predictor_id: int, df: pd.DataFrame) -> None: try: predictor_record = session.query(db.Predictor).filter_by(id=predictor_id).first() assert predictor_record is not None fs_store = FsStore() config = Config() predictor_record.data = {'training_log': 'training'} session.commit() predictor: lightwood.PredictorInterface = lightwood.predictor_from_code(predictor_record.code) predictor.learn(df) session.refresh(predictor_record) fs_name = f'predictor_{predictor_record.company_id}_{predictor_record.id}' pickle_path = os.path.join(config['paths']['predictors'], fs_name) predictor.save(pickle_path) fs_store.put(fs_name, fs_name, config['paths']['predictors']) predictor_record.data = predictor.model_analysis.to_dict() predictor_record.dtype_dict = predictor.dtype_dict session.commit() dbw = DatabaseWrapper(predictor_record.company_id) mi = ModelInterfaceWrapper(ModelInterface(), predictor_record.company_id) dbw.register_predictors([mi.get_model_data(predictor_record.name)]) except Exception as e: session.refresh(predictor_record) predictor_record.data = {'error': f'{traceback.format_exc()}\nMain error: {e}'} session.commit() raise e
def __init__(self, model_interface, ai_table, data_store, datasource_interface): self.config = Config() self.model_interface = model_interface self.ai_table = ai_table self.data_store = data_store self.datasource_interface = datasource_interface
def _get_integration_record_data(integration_record, sensitive_info=True): if integration_record is None or integration_record.data is None: return None data = deepcopy(integration_record.data) if data.get('password', None) is None: data['password'] = '' data['date_last_update'] = deepcopy(integration_record.updated_at) bundle_path = data.get('secure_connect_bundle') mysql_ssl_ca = data.get('ssl_ca') mysql_ssl_cert = data.get('ssl_cert') mysql_ssl_key = data.get('ssl_key') if (data.get('type') in ('mysql', 'mariadb') and (_is_not_empty_str(mysql_ssl_ca) or _is_not_empty_str(mysql_ssl_cert) or _is_not_empty_str(mysql_ssl_key)) or data.get('type') in ('cassandra', 'scylla') and bundle_path is not None): fs_store = FsStore() integrations_dir = Config()['paths']['integrations'] folder_name = f'integration_files_{integration_record.company_id}_{integration_record.id}' integration_dir = os.path.join(integrations_dir, folder_name) fs_store.get(folder_name, integration_dir, integrations_dir) if not sensitive_info: if 'password' in data: data['password'] = None if (data.get('type') == 'redis' and isinstance(data.get('connection'), dict) and 'password' in data['connection']): data['connection'] = None data['id'] = integration_record.id return data
def __init__(self, original_model_interface, original_data_store, company_id=None) -> object: """ Initialize the session :param company_id: """ self.username = None self.auth = False self.company_id = company_id self.logging = log self.integration = None self.integration_type = None self.database = None self.config = Config() self.ai_table = AITableStore(company_id=company_id) self.data_store = DataStoreWrapper(data_store=original_data_store, company_id=company_id) self.model_interface = ModelInterfaceWrapper( model_interface=original_model_interface, company_id=company_id) self.datahub = init_datahub(model_interface=self.model_interface, ai_table=self.ai_table, data_store=self.data_store, company_id=company_id) self.prepared_stmts = {} self.packet_sequence_number = 0
def initialize_interfaces(app): app.default_store = DataStore() app.naitve_interface = NativeInterface() app.custom_models = CustomModels() app.dbw = DatabaseWrapper() config = Config() app.config_obj = config
def __init__(self, server, company_id=None) -> object: """ Initialize the session :param company_id: """ self.username = None self.auth = False self.company_id = company_id self.logging = log self.integration = None self.integration_type = None self.database = None self.config = Config() self.data_store = WithKWArgsWrapper(server.original_data_store, company_id=company_id) self.model_interface = WithKWArgsWrapper( server.original_model_interface, company_id=company_id) self.integration_controller = WithKWArgsWrapper( server.original_integration_controller, company_id=company_id) self.view_interface = WithKWArgsWrapper( server.original_view_controller, company_id=company_id) self.datahub = init_datahub(self) self.prepared_stmts = {} self.packet_sequence_number = 0
def __init__(self, ray_based): self.config = Config() self.fs_store = FsSotre() self.company_id = os.environ.get('MINDSDB_COMPANY_ID', None) self.dbw = DatabaseWrapper() self.predictor_cache = {} self.ray_based = ray_based
def start(config, initial=False): if not initial: print( '\n\nWarning, this process should not have been started... nothing is "wrong" but it needlessly ate away a tiny bit of precious comute !\n\n' ) config = Config(config) if not logging.root.handlers: rootLogger = logging.getLogger() outStream = logging.StreamHandler(sys.stdout) outStream.addFilter(lambda record: record.levelno <= logging.INFO) rootLogger.addHandler(outStream) errStream = logging.StreamHandler(sys.stderr) errStream.addFilter(lambda record: record.levelno > logging.INFO) rootLogger.addHandler(errStream) initialize_static(config) app, api = initialize_flask(config) initialize_interfaces(config, app) api.add_namespace(predictor_ns) api.add_namespace(datasource_ns) api.add_namespace(utils_ns) api.add_namespace(conf_ns) @api.errorhandler(Exception) def handle_exception(e): # pass through HTTP errors if isinstance(e, HTTPException): return {'message': str(e)}, e.code, e.get_response().headers name = getattr(type(e), '__name__') or 'Unknown error' return {'message': f'{name}: {str(e)}'}, 500 port = config['api']['http']['port'] host = config['api']['http']['host'] print(f"Start on {host}:{port}") server = os.environ.get('MINDSDB_DEFAULT_SERVER', 'waitress') if server.lower() == 'waitress': serve(app, port=port, host=host) elif server.lower() == 'flask': app.run(debug=False, port=port, host=host) elif server.lower() == 'gunicorn': try: from mindsdb.api.http.gunicorn_wrapper import StandaloneApplication except ImportError: print( "Gunicorn server is not available by default. If you wish to use it, please install 'gunicorn'" ) return options = { 'bind': f'{host}:{port}', 'workers': min(max(multiprocessing.cpu_count(), 2), 3) } StandaloneApplication(app, options).run()
def __init__(self): self.config = Config() self.fs_store = FsSotre() self.company_id = os.environ.get('MINDSDB_COMPANY_ID', None) self.dir = self.config.paths['datasources'] self.mindsdb_native = NativeInterface()
def start(config, initial=False): if not initial: print( '\n\nWarning, this process should not have been started... nothing is "wrong" but it needlessly ate away a tiny bit of precious compute !\n\n' ) config = Config(config) MysqlProxy.startProxy(config)
def start(config, verbose=False): config = Config(config) if verbose: config['log']['level']['console'] = 'DEBUG' initialize_log(config, 'mysql', wrap_print=True) MysqlProxy.startProxy(config)
def start(verbose=False): config = Config() if verbose: config.set(['log', 'level', 'console'], 'DEBUG') initialize_log(config, 'mysql', wrap_print=True) MysqlProxy.startProxy(config)
def start(config, verbose=False): config = Config(config) if verbose: config['log']['level']['console'] = 'DEBUG' initialize_log(config, 'mongodb', wrap_print=True) run_server(config)
def start(verbose=False): config = Config() if verbose: config.set(['log', 'level', 'console'], 'DEBUG') initialize_log(config, 'mongodb', wrap_print=True) run_server(config)
def run_update(name: str, company_id: int): original_name = name name = f'{company_id}@@@@@{name}' fs_store = FsStore() config = Config() data_store = DataStoreWrapper(DataStore(), company_id) try: predictor_record = Predictor.query.filter_by(company_id=company_id, name=original_name).first() assert predictor_record is not None predictor_record.update_status = 'updating' session.commit() ds = data_store.get_datasource_obj(None, raw=False, id=predictor_record.datasource_id) df = ds.df problem_definition = predictor_record.learn_args problem_definition['target'] = predictor_record.to_predict[0] if 'join_learn_process' in problem_definition: del problem_definition['join_learn_process'] # Adapt kwargs to problem definition if 'timeseries_settings' in problem_definition: problem_definition['timeseries_settings'] = problem_definition['timeseries_settings'] if 'stop_training_in_x_seconds' in problem_definition: problem_definition['time_aim'] = problem_definition['stop_training_in_x_seconds'] json_ai = lightwood.json_ai_from_problem(df, problem_definition) predictor_record.json_ai = json_ai.to_dict() predictor_record.code = lightwood.code_from_json_ai(json_ai) predictor_record.data = {'training_log': 'training'} session.commit() predictor: lightwood.PredictorInterface = lightwood.predictor_from_code(predictor_record.code) predictor.learn(df) fs_name = f'predictor_{predictor_record.company_id}_{predictor_record.id}' pickle_path = os.path.join(config['paths']['predictors'], fs_name) predictor.save(pickle_path) fs_store.put(fs_name, fs_name, config['paths']['predictors']) predictor_record.data = predictor.model_analysis.to_dict() # type: ignore session.commit() predictor_record.lightwood_version = lightwood.__version__ predictor_record.mindsdb_version = mindsdb_version predictor_record.update_status = 'up_to_date' session.commit() except Exception as e: log.error(e) predictor_record.update_status = 'update_failed' # type: ignore session.commit() return str(e)
def __init__(self): self.config = Config() self.fs_store = FsSotre() self.company_id = os.environ.get('MINDSDB_COMPANY_ID', None) self.dbw = DatabaseWrapper() self.storage_dir = self.config['paths']['custom_models'] os.makedirs(self.storage_dir, exist_ok=True) self.model_cache = {} self.mindsdb_native = NativeInterface() self.dbw = DatabaseWrapper()
def run_fit(predictor_id: int, df: pd.DataFrame) -> None: try: predictor_record = Predictor.query.with_for_update().get(predictor_id) assert predictor_record is not None fs_store = FsStore() config = Config() predictor_record.data = {'training_log': 'training'} session.commit() predictor: lightwood.PredictorInterface = lightwood.predictor_from_code( predictor_record.code) predictor.learn(df) session.refresh(predictor_record) fs_name = f'predictor_{predictor_record.company_id}_{predictor_record.id}' pickle_path = os.path.join(config['paths']['predictors'], fs_name) predictor.save(pickle_path) fs_store.put(fs_name, fs_name, config['paths']['predictors']) predictor_record.data = predictor.model_analysis.to_dict() # getting training time for each tried model. it is possible to do # after training only fit_mixers = list(predictor.runtime_log[x] for x in predictor.runtime_log if isinstance(x, tuple) and x[0] == "fit_mixer") submodel_data = predictor_record.data.get("submodel_data", []) # add training time to other mixers info if submodel_data and fit_mixers and len(submodel_data) == len( fit_mixers): for i, tr_time in enumerate(fit_mixers): submodel_data[i]["training_time"] = tr_time predictor_record.data["submodel_data"] = submodel_data predictor_record.dtype_dict = predictor.dtype_dict session.commit() dbw = DatabaseWrapper(predictor_record.company_id) mi = WithKWArgsWrapper(ModelInterface(), company_id=predictor_record.company_id) except Exception as e: session.refresh(predictor_record) predictor_record.data = { 'error': f'{traceback.format_exc()}\nMain error: {e}' } session.commit() raise e try: dbw.register_predictors([mi.get_model_data(predictor_record.name)]) except Exception as e: log.warn(e)
def run(self): ''' running at subprocess due to ValueError: signal only works in main thread this is work for celery worker here? ''' import mindsdb_native import setproctitle try: setproctitle.setproctitle('mindsdb_native_process') except Exception: pass config = Config() fs_store = FsSotre() company_id = os.environ.get('MINDSDB_COMPANY_ID', None) name, from_data, to_predict, kwargs, datasource_id = self._args mdb = mindsdb_native.Predictor(name=name, run_env={'trigger': 'mindsdb'}) predictor_record = Predictor.query.filter_by(company_id=company_id, name=name).first() predictor_record.datasource_id = datasource_id predictor_record.to_predict = to_predict predictor_record.version = mindsdb_native.__version__ predictor_record.data = { 'name': name, 'status': 'training' } #predictor_record.datasource_id = ... <-- can be done once `learn` is passed a datasource name session.commit() to_predict = to_predict if isinstance(to_predict, list) else [to_predict] data_source = getattr(mindsdb_native, from_data['class'])(*from_data['args'], **from_data['kwargs']) try: mdb.learn( from_data=data_source, to_predict=to_predict, **kwargs ) except Exception: pass fs_store.put(name, f'predictor_{company_id}_{predictor_record.id}', config['paths']['predictors']) model_data = mindsdb_native.F.get_model_data(name) predictor_record = Predictor.query.filter_by(company_id=company_id, name=name).first() predictor_record.data = model_data session.commit() DatabaseWrapper().register_predictors([model_data])
def start(config, verbose=False): config = Config(config) if verbose: config['log']['level']['console'] = 'INFO' initialize_log(config, 'http', wrap_print=True) initialize_static(config) app, api = initialize_flask(config) initialize_interfaces(config, app) api.add_namespace(predictor_ns) api.add_namespace(datasource_ns) api.add_namespace(utils_ns) api.add_namespace(conf_ns) @api.errorhandler(Exception) def handle_exception(e): # pass through HTTP errors if isinstance(e, HTTPException): return {'message': str(e)}, e.code, e.get_response().headers name = getattr(type(e), '__name__') or 'Unknown error' return {'message': f'{name}: {str(e)}'}, 500 port = config['api']['http']['port'] host = config['api']['http']['host'] server = os.environ.get('MINDSDB_DEFAULT_SERVER', 'waitress') if server.lower() == 'waitress': serve(app, port=port, host=host) elif server.lower() == 'flask': # that will 'disable access' log in console log = logging.getLogger('werkzeug') log.setLevel(logging.WARNING) app.run(debug=False, port=port, host=host) elif server.lower() == 'gunicorn': try: from mindsdb.api.http.gunicorn_wrapper import StandaloneApplication except ImportError: print( "Gunicorn server is not available by default. If you wish to use it, please install 'gunicorn'" ) return options = { 'bind': f'{host}:{port}', 'workers': min(max(multiprocessing.cpu_count(), 2), 3) } StandaloneApplication(app, options).run()
def __init__(self): self.config = Config() self.location = self.config['permanent_storage']['location'] if self.location == 'local': pass elif self.location == 's3': if 's3_credentials' in self.config['permanent_storage']: self.s3 = boto3.client('s3', **self.config['permanent_storage']['s3_credentials']) else: self.s3 = boto3.client('s3') self.bucket = self.config['permanent_storage']['bucket'] else: raise Exception('Location: ' + self.location + ' not supported')
def get_current_gui_version() -> LooseVersion: config = Config() static_path = Path(config['paths']['static']) version_txt_path = static_path.joinpath('version.txt') current_gui_version = None if version_txt_path.is_file(): with open(version_txt_path, 'rt') as f: current_gui_version = f.readline() current_gui_lv = None if current_gui_version is None else LooseVersion(current_gui_version) return current_gui_lv
def delete_datasource(self, name, company_id=None): datasource_record = Datasource.query.filter_by(company_id=company_id, name=name).first() if not Config()["force_datasource_removing"]: linked_models = Predictor.query.filter_by(company_id=company_id, datasource_id=datasource_record.id).all() if linked_models: raise Exception("Can't delete {} datasource because there are next models linked to it: {}".format(name, [model.name for model in linked_models])) session.delete(datasource_record) session.commit() self.fs_store.delete(f'datasource_{company_id}_{datasource_record.id}') try: shutil.rmtree(os.path.join(self.dir, f'{company_id}@@@@@{name}')) except Exception: pass
def run_environment(config, apis=['mysql'], override_integration_config={}, override_api_config={}, mindsdb_database='mindsdb', clear_storage=True): temp_config_path = prepare_config(config, mindsdb_database, override_integration_config, override_api_config, clear_storage) config = Config(temp_config_path) api_str = ','.join(apis) sp = subprocess.Popen([ 'python3', '-m', 'mindsdb', '--api', api_str, '--config', temp_config_path, '--verbose' ], close_fds=True, stdout=OUTPUT, stderr=OUTPUT) atexit.register(stop_mindsdb, sp=sp) async def wait_port_async(port, timeout): start_time = time.time() started = is_port_in_use(port) while (time.time() - start_time) < timeout and started is False: await asyncio.sleep(1) started = is_port_in_use(port) return started async def wait_apis_start(ports): futures = [wait_port_async(port, 60) for port in ports] success = True for i, future in enumerate(asyncio.as_completed(futures)): success = success and await future return success ports_to_wait = [config['api'][api]['port'] for api in apis] ioloop = asyncio.get_event_loop() if ioloop.is_closed(): ioloop = asyncio.new_event_loop() success = ioloop.run_until_complete(wait_apis_start(ports_to_wait)) ioloop.close() if not success: raise Exception('Cant start mindsdb apis') CONFIG.MINDSDB_STORAGE_PATH = config.paths['predictors'] mdb = NativeInterface(config) datastore = DataStore(config) return mdb, datastore
def run_learn(name, from_data, to_predict, kwargs, datasource_id): import mindsdb_native import mindsdb_datasources import mindsdb create_process_mark('learn') config = Config() fs_store = FsSotre() company_id = os.environ.get('MINDSDB_COMPANY_ID', None) mdb = mindsdb_native.Predictor(name=name, run_env={'trigger': 'mindsdb'}) predictor_record = Predictor.query.filter_by(company_id=company_id, name=name).first() predictor_record.datasource_id = datasource_id predictor_record.to_predict = to_predict predictor_record.native_version = mindsdb_native.__version__ predictor_record.mindsdb_version = mindsdb_version predictor_record.learn_args = {'to_predict': to_predict, 'kwargs': kwargs} predictor_record.data = {'name': name, 'status': 'training'} session.commit() to_predict = to_predict if isinstance(to_predict, list) else [to_predict] data_source = getattr(mindsdb_datasources, from_data['class'])(*from_data['args'], **from_data['kwargs']) try: mdb.learn(from_data=data_source, to_predict=to_predict, **kwargs) except Exception as e: log = logging.getLogger('mindsdb.main') log.error(f'Predictor learn error: {e}') predictor_record.data = {'name': name, 'status': 'error'} session.commit() delete_process_mark('learn') return fs_store.put(name, f'predictor_{company_id}_{predictor_record.id}', config['paths']['predictors']) model_data = mindsdb_native.F.get_model_data(name) predictor_record = Predictor.query.filter_by(company_id=company_id, name=name).first() predictor_record.data = model_data session.commit() DatabaseWrapper().register_predictors([model_data]) delete_process_mark('learn')
def remove_db_integration(name, company_id): integration_record = session.query(Integration).filter_by( company_id=company_id, name=name).first() integrations_dir = Config()['paths']['integrations'] folder_name = f'integration_files_{company_id}_{integration_record.id}' integration_dir = os.path.join(integrations_dir, folder_name) if os.path.isdir(integration_dir): shutil.rmtree(integration_dir) try: FsStore().delete(folder_name) except Exception: pass session.delete(integration_record) session.commit()
def start(config, initial=False): if not initial: print('\n\nWarning, this process should not have been started... nothing is "wrong" but it needlessly ate away a tiny bit of precious comute !\n\n') config = Config(config) if not logging.root.handlers: rootLogger = logging.getLogger() outStream = logging.StreamHandler(sys.stdout) outStream.addFilter(lambda record: record.levelno <= logging.INFO) rootLogger.addHandler(outStream) errStream = logging.StreamHandler(sys.stderr) errStream.addFilter(lambda record: record.levelno > logging.INFO) rootLogger.addHandler(errStream) mindsdb.CONFIG.MINDSDB_DATASOURCES_PATH = os.path.join(mindsdb.CONFIG.MINDSDB_STORAGE_PATH, 'datasources') mindsdb.CONFIG.MINDSDB_TEMP_PATH = os.path.join(mindsdb.CONFIG.MINDSDB_STORAGE_PATH, 'tmp') os.makedirs(mindsdb.CONFIG.MINDSDB_STORAGE_PATH, exist_ok=True) os.makedirs(mindsdb.CONFIG.MINDSDB_DATASOURCES_PATH, exist_ok=True) os.makedirs(mindsdb.CONFIG.MINDSDB_TEMP_PATH, exist_ok=True) app, api = initialize_flask(config) initialize_interfaces(config, app) api.add_namespace(predictor_ns) api.add_namespace(datasource_ns) api.add_namespace(utils_ns) api.add_namespace(conf_ns) @api.errorhandler(Exception) def handle_exception(e): # pass through HTTP errors if isinstance(e, HTTPException): return {'message': str(e)}, e.code, e.get_response().headers name = getattr(type(e), '__name__') or 'Unknown error' return {'message': f'{name}: {str(e)}'}, 500 port = config['api']['http']['port'] host = config['api']['http']['host'] print(f"Start on {host}:{port}") options = { 'bind': f'{host}:{port}', 'workers': min(max(multiprocessing.cpu_count(), 2), 3) } StandaloneApplication(app, options).run()
def setUpClass(cls): cls.config = Config(TEST_CONFIG) cls.initial_integrations_names = list( cls.config['integrations'].keys()) mdb, datastore = run_environment(cls.config, apis=['http'], override_integration_config={ 'default_mariadb': { 'publish': True }, 'default_clickhouse': { 'publish': True } }, mindsdb_database=MINDSDB_DATABASE) cls.mdb = mdb
def __init__(self, name, predictor, stream_in, stream_out, anomaly_stream=None, learning_stream=None, learning_threshold=100): self.name = name self.predictor = predictor self.stream_in = stream_in self.stream_out = stream_out self.anomaly_stream = anomaly_stream self.learning_stream = learning_stream self.learning_threshold = learning_threshold self.learning_data = [] self.company_id = os.environ.get('MINDSDB_COMPANY_ID', None) self.stop_event = Event() self.model_interface = ModelInterfaceWrapper(ModelInterface()) self.data_store = DataStore() self.config = Config() p = db.session.query(db.Predictor).filter_by( company_id=self.company_id, name=self.predictor).first() if p is None: raise Exception(f'Predictor {predictor} doesn\'t exist') self.target = p.to_predict[0] ts_settings = p.learn_args.get('timeseries_settings', None) if not ts_settings['is_timeseries']: ts_settings = None if ts_settings is None: self.thread = Thread(target=StreamController._make_predictions, args=(self, )) else: self.ts_settings = ts_settings self.thread = Thread(target=StreamController._make_ts_predictions, args=(self, )) self.thread.start()
def start(config, initial=False): if not initial: print( '\n\nWarning, this process should not have been started... nothing is "wrong" but it needlessly ate away a tiny bit of precious comute !\n\n' ) config = Config(config) debug = False if not logging.root.handlers: rootLogger = logging.getLogger() outStream = logging.StreamHandler(sys.stdout) outStream.addFilter(lambda record: record.levelno <= logging.INFO) rootLogger.addHandler(outStream) errStream = logging.StreamHandler(sys.stderr) errStream.addFilter(lambda record: record.levelno > logging.INFO) rootLogger.addHandler(errStream) mindsdb.CONFIG.MINDSDB_DATASOURCES_PATH = os.path.join( mindsdb.CONFIG.MINDSDB_STORAGE_PATH, 'datasources') mindsdb.CONFIG.MINDSDB_TEMP_PATH = os.path.join( mindsdb.CONFIG.MINDSDB_STORAGE_PATH, 'tmp') os.makedirs(mindsdb.CONFIG.MINDSDB_STORAGE_PATH, exist_ok=True) os.makedirs(mindsdb.CONFIG.MINDSDB_DATASOURCES_PATH, exist_ok=True) os.makedirs(mindsdb.CONFIG.MINDSDB_TEMP_PATH, exist_ok=True) app, api = initialize_flask(config) initialize_interfaces(config, app) api.add_namespace(predictor_ns) api.add_namespace(datasource_ns) api.add_namespace(utils_ns) api.add_namespace(conf_ns) print( f"Start on {config['api']['http']['host']}:{config['api']['http']['port']}" ) app.run(debug=debug, port=config['api']['http']['port'], host=config['api']['http']['host'])
def update_static(): ''' Update Scout files basing on compatible-config.json content. Files will be downloaded and updated if new version of GUI > current. Current GUI version stored in static/version.txt. ''' config = Config() log = get_log('http') static_path = Path(config['paths']['static']) last_gui_version_lv = get_last_compatible_gui_version() current_gui_version_lv = get_current_gui_version() if last_gui_version_lv is False: return False if current_gui_version_lv is not None: if current_gui_version_lv >= last_gui_version_lv: return True log.info( f'New version of GUI available ({last_gui_version_lv.vstring}). Downloading...' ) temp_dir = tempfile.mkdtemp(prefix='mindsdb_gui_files_') success = download_gui(temp_dir, last_gui_version_lv.vstring) if success is False: shutil.rmtree(temp_dir) return False temp_dir_for_rm = tempfile.mkdtemp(prefix='mindsdb_gui_files_') shutil.rmtree(temp_dir_for_rm) shutil.copytree(str(static_path), temp_dir_for_rm) shutil.rmtree(str(static_path)) shutil.copytree(temp_dir, str(static_path)) shutil.rmtree(temp_dir_for_rm) log.info(f'GUI version updated to {last_gui_version_lv.vstring}') return True