def reload_recursive_ex(module): try: importlib.reload(module) except ImportError as err: logger.exception(err) logger.error("module '{}' could not be reloaded.".format(module)) return if reload_func: for func_names in ls_func_names: if func_names in dir(module): ls_functions = getattr(module, func_names) reload_functions(module, ls_functions) logger.debug("module '{}' reloaded!".format(module.__name__)) for module_child in vars( module).values(): # search subpackages in vars(module) if isinstance(module_child, types.ModuleType): # if it is a module fn_child = getattr(module_child, "__file__", None) if (fn_child is not None ) and fn_child.startswith(fn_dir): # if it is a subpackage if fn_child not in module_visit: # if module has not benn reloaded yet # print("reloading:", fn_child, "from", module) module_visit.add(fn_child) reload_recursive_ex( module_child) # reload subpackages of this module
def handle_file_error(err, func, path, args=None, kwargs=None, pos_path=0, key_path=None, change_path_func=save_file, title='', msg='', return_if_ignore=None): """If PermissionError when opening/saving file, propose to retry, change file path or cancel :param err: exception :param func: function to execute if the user wants to retry :param path: file path :param args: args to pass to func :param kwargs: kwargs to pass to func :param pos_path: position of the positional argument path in func (only if key_path is None) :param key_path: name of the keyword argument path in func (if None, positional argument is used) :param change_path_func: function to get a new path, with no positional argument and 'initialdir' keyword argument :param title: title of the error :param msg: message of the error :param return_if_ignore: return if Ignore option is selected :return: """ logger.debug(err) args = args or [] kwargs = kwargs or {} title = title or 'File error!' msg = msg or "Unknown error with file '{}'. \nOriginal error: {}".format(path, err) logger.warning('User action needed!') res = messagebox.askcustomquestion(title=title, message=msg, choices=["Retry", "Rename automatically", "Change file path", "Ignore", "Debug (developer only)", "Cancel"]) if res == "Retry": if key_path is not None: kwargs[key_path] = path else: args.insert(pos_path, path) return func(*args, **kwargs) if res == "Rename automatically": n_path = _handle_existing_file_conflict(path=path, overwrite='rename') if key_path is not None: kwargs[key_path] = n_path else: args.insert(pos_path, n_path) return func(*args, **kwargs) elif res == "Change file path": initialdir = Path(path).dirname if Path(path).dirname.exists else None if key_path is not None: kwargs[key_path] = change_path_func(initialdir=initialdir) else: args.insert(pos_path, change_path_func(initialdir=initialdir)) return func(*args, **kwargs) elif res == "Ignore": logger.warning("Function ignored!") logger.debug("Function '{}' with path '{}' ignored!") return return_if_ignore elif res == "Debug (developer only)": pdb.set_trace() elif res in [None, "Cancel"]: err = UnknownError if not isinstance(err, BaseException) else err logger.exception(err) raise err.__class__(err) else: raise TypeError("Bad return of function 'messagebox.askcustomquestion': '{}'".format(res))
def test_out_function(self): logger.info("测试数字和元组数字是否相等!!") try: assert 3 == (4, ) except AssertionError: logger.exception("测试数字和元组数字是否相等失败!!") raise else: logger.info("测试数字和元组数字是否相等通过!!")
def _single_item_conversion(item, key=None, error='ignore', drop_none=False, drop_empty_iterable=False): if key is None: logger.debug( "Conversion bypassed because argument 'key' is None. Returning None." ) return item try: if item is None: return None if isiterable(item): # if iterable object _v = type(item)(_single_item_conversion( s_item, key=key, error=error, drop_none=drop_none, drop_empty_iterable=drop_empty_iterable) for s_item in item) else: _v = FILE_TO_KEY.get(key, str)(item) if drop_none and isiterable(_v): _v = type(_v)(s_item for s_item in _v if s_item is not None) if drop_empty_iterable and not _v: _v = None except (ValueError, TypeError, SyntaxError) as err: if error == 'ignore': logger.debug( "Conversion error with flag 'ignore'. Returning the original string '{}'." .format(item)) return item elif error == 'drop': logger.debug( "Conversion error with flag 'drop'. Returning None value (original string: '{}'." .format(item)) return None elif error == 'auto-conversion': try: n_item = ast.literal_eval(item) logger.debug( "Conversion error with flag 'auto-conversion'. " "Returning the evaluation of string '{}'.".format(item)) return n_item except (ValueError, SyntaxError): logger.debug( "Conversion error with flag 'auto-conversion'. Auto-conversion failed." "Returning the original string '{}'.".format(item)) return item else: logger.exception(err) logger.debug( "Conversion error with flag 'error'. The original string was '{}'." .format(item)) raise err.__class__(err) return _v
def test_bb(self): logger.info("测试int和str ") try: a = '1' assert 1 in a except AssertionError: logger.exception('测试int和str 失败!!') raise else: logger.info("测试int和str 通过!!")
def _handle_existing_file_conflict(path: Path, overwrite='ask', backup=False, **kwargs) -> Union[Path, None]: """Handle conflict if a file already exist by opening adapted dialog.""" # overwrite 'ask': ask user to modify overwrite arg into 'overwrite' (Yes) or 'rename' (No) or return None (Cancel) if overwrite == 'ask': logger.warning('User action needed!') res = messagebox.askyesnocancel(title="File existing", message="File {} already exists.\nDo you want to overwrite it?" "\n\nIf you select 'No', the file will be " "renamed automatically.".format(path)) if res is None: logger.info("'Save file' operation cancelled by the user.".format(path)) logger.debug("The path 'None' will be returned.") return None if res: overwrite = 'overwrite' else: overwrite = 'rename' # overwrite 'rename' or False: add '-i' at the end of the path to make it unique, where 'i' is an integer. if overwrite == 'rename' or overwrite is False: r_path, r_ext = path.splitext # def rename_method1(r_path, sep='-'):#todo ls_end = re.findall(r'-(\d+)$', r_path) if ls_end: # if the path already ends by '-i', change end to 'i+1' end = ls_end[0] r_path = r_path[:-(len(end) + 1)] added_ending = "-{}".format(int(end) + 1) else: added_ending = "-1" n_path = r_path + added_ending + r_ext logger.debug("Path {} changed to {} (renaming)".format(path, n_path)) return save_file(n_path, overwrite=overwrite, backup=backup, **kwargs) # backup True: backup the old file if backup and path.isfile: suffix = datetime.datetime.now().strftime("-%Y-%m-%d_%H-%M_") + uuid.uuid4().hex[:5] try: shutil.copyfile(path, path.radix + suffix + path.ext) except (PermissionError, FileNotFoundError) as err: logger.exception(err) logger.error("Failed to backup previous configuration file.") # overwrite 'overwrite' or True: do not modify the path and make the old file writable to allow overwriting if overwrite == 'overwrite' or overwrite is True: logger.debug("File {} will be overwritten".format(path)) _set_writable(path) # overwrite 'ignore': do nothing elif overwrite == 'ignore': pass # other case of overwrite: do nothing (same as 'ignore') else: logger.warning("Unexpected argument 'overwrite'! File {} will be overwritten".format(path)) return path
def test_a(self): logger.info("测试数字和字符串数字是否相等!") try: a = 1 assert 1 is a assert 1 == '1' except AssertionError: logger.exception('测试数字和字符串数字是否相等失败!!') raise else: logger.info("测试数字和字符串是否相等通过!!")
def result(self): """Returns result""" if not self._changes: return self._initial_value key = self.result_keys try: res = self._choices[key]['value'] except KeyError as err_msg: logger.exception(err_msg) logger.error( "Bad key '{}' for Radiobutton widget. Use a string or int as key to avoid this error.\n" "None value is returned".format(key)) return None return res
def read_config(cls, path, auto_cast=True, anomaly_flag='warning'): """Returns a config_dict read from a INI file.""" # WARNING: No check of input arguments ! # Read the configuration file with configparser config_parser = configparser.ConfigParser() try: config_parser.read(path, encoding=ENCODING) except (configparser.Error, ValueError, KeyError, TypeError) as err: logger.exception(err) msg = "The configuration could not be loaded!\n" \ "Please check that the configuration file is correct.\n" \ "Original error: {}".format(err) raise_anomaly(flag=anomaly_flag, error=err.__class__, title="Configuration loading failed!", message=msg) return None return ConfigDict(config_parser, auto_cast=auto_cast)
def write_config(cls, path, config_dict, write_flags=False, anomaly_flag='warning'): # WARNING: No check of input arguments ! # config_dict = convert_dict_to_str(config_dict) if write_flags else config_dict # WRONG: ConfigDict not convertible! # Write Configparser object to disk try: with open(path, mode='w', encoding=ENCODING, newline=None) as file: file.write(config_dict.to_str(write_flags=write_flags)) except (configparser.Error, PermissionError, FileNotFoundError) as err: logger.exception(err) msg = "Configuration could not be written to disk!\n" \ "Original error: {}".format(err) raise_anomaly(flag=anomaly_flag, error=err.__class__, title="Configuration writing failed!", message=msg) return None logger.info("Configuration successfully written to disk: {}".format(path)) # logger.debug("Configuration written: {}".format(config_dict)) return path
def run(self): logger.debug("start task with func '{}'".format(self.func_name)) try: self.func(*self.args, **self.kwargs) msg = "'{}' successfully ended.".format(self.func_name) logger.info( "Function '{}' successfully ended.\n***************\n".format( self.func_name)) except Exception as err: logger.exception(err) msg = "'{}' ended with error.".format(self.func_name) logger.error( "Function '{}' ended with error.\n***************\n".format( self.func_name)) self.queue.put( msg ) # add func name to queue to indicate that the task is finished logger.debug("end task with func '{}'".format(self.func_name))
def write_config_bug(cls, path, config_dict, backup=True, overwrite=True, auto_mkdir=True, write_flags=False, anomaly_flag='warning'): # todo buggy method # WARNING: No check of input arguments ! # Get path path = save_file(path, overwrite=overwrite, backup=backup, auto_mkdir=auto_mkdir) # Load Configparser object config_parser = cls._write_configparser(config_dict, write_flags=write_flags) # Write Configparser object to disk try: with open(path, mode='w', encoding=ENCODING, newline=None) as file: config_parser.write(file) except (configparser.Error, PermissionError, FileNotFoundError) as err: logger.exception(err) msg = "Configuration could not be written to disk!\n" \ "Original error: {}".format(err) raise_anomaly(flag=anomaly_flag, error=err.__class__, title="Configuration writing failed!", message=msg) return None logger.info("Configuration successfully written to disk: {}".format(path)) # logger.debug("Configuration written: {}".format(config_dict)) return path
def _write_excel(path, dataframes, sheet_names, index=False, **kwargs): """Save dataframes to an Excel workbook. :param path: output path :param dataframes: list of dataframes :param sheet_names: list of sheet names (same index as dataframes) :param index: if True, index names are exported :param kwargs: keyword arguments for pd.DataFrame.to_excel function :return: final output path """ if path is None or path.isnone: logger.warning('No path set to write data to Excel! No file has been created.') return None try: logger.debug("Trying to open file '{}'".format(path)) with pd.ExcelWriter(path) as writer: logger.debug("File {} opened.".format(path)) for df, sheet_name in zip(dataframes, sheet_names): if isinstance(df.columns, pd.MultiIndex): index = True # index must be True if MultiIndex columns, otherwise NotImplementedError is raised df.to_excel(writer, sheet_name=sheet_name, index=index, **kwargs) logger.debug("Sheet {} written.".format(sheet_name)) logger.debug("File {} closed.".format(path)) except PermissionError as err: logger.exception(err) path = handle_permission_error(err, func=_write_excel, path=path, args=[dataframes, sheet_names, index], kwargs=kwargs, change_path_func=save_file, handle_read_only_error=True) except ValueError as err: if str(err).startswith("No engine for filetype"): path = handle_bad_extension_error(err, func=_write_excel, path=path, args=[dataframes, sheet_names, index], kwargs=kwargs, change_path_func=save_file, extension=".xlsx") else: raise err except FileNotFoundError as err: logger.exception(err) path = handle_file_not_found_error(err, func=_write_excel, path=path, args=[dataframes, sheet_names, index], kwargs=kwargs, change_path_func=save_file) return path
def sending_notifications(self): for user in self.users: chat_id = user['chat_id'] week = user['week'] day_now = user['day'] time = user['time'] group = user['group'] notifications = user['notifications'] try: schedule = self.storage.get_schedule(group=group)['schedule'] except Exception as e: logger.exception(f'Error (group: {group}):\n{e}') continue # Получение расписания из нужного дня. lessons = tools.get_schedule_from_right_day(schedule=schedule, day_now=day_now) # если не нашлось переходем к след user if not lessons: continue lessons_for_reminders = tools.forming_message_text(lessons=lessons, week=week, time=time) # если пары не нашлись переходим к след user if not lessons_for_reminders: continue # Отправляем сообщение пользователю text = f'Через {notifications} минут пара\n' \ f'{lessons_for_reminders}' if self.platform == 'tg': try: self.bot.send_message(chat_id=chat_id, text=text) except Exception as e: logger.exception(f'---TG---\n{e}') elif self.platform == 'vk': try: logger.info(f'vk send user_id: {chat_id}') self.bot.method('messages.send', {'user_id': chat_id, 'message': text, 'random_id': 0}) except Exception as e: logger.exception(f'---VK---\n{e}')
def save_file(path: Union[Path, str] = None, config_dict=None, config_key=None, return_on_cancellation=Path(None), behavior_on_cancellation='warning', auto_mkdir=True, extension=None, replace_ext=False, filetype=None, overwrite='ask', backup=False, **kwargs) -> Path: """Check the path to save a file. :param path: path or None :param config_dict: dictionary-like object containing the configuration :param config_key: key of config_dict to get path (replaces path argument) :param return_on_cancellation: return on user cancellation. Default: Path(None) (highly recommended) :param behavior_on_cancellation: error flag used to raise anomaly 'raise_no_file_selected_anomaly' on cancellation . Must be 'ask', 'ignore', 'warning', or 'error'. :param auto_mkdir: if True, try to create output directories if they don't exist :param filetype: filetype in FILETYPE_TO_FILEDIALOG_FILETYPES keys. If filetype is None, extension is not checked. :param extension: final extension to check. If extension is None, extension is not checked. :param replace_ext: if True, replaces extension instead of adding one :param overwrite: bool or flag 'ask', 'rename', 'ignore', 'overwrite', used in case file already exists :param backup: bool, used in case file already exists :param kwargs: for filedialog :return: path """ # Check of input arguments. path = Path(check_path_arguments(path, config_dict, config_key)) if 'filetypes' not in kwargs: kwargs.update({'filetypes': FILETYPE_TO_FILEDIALOG_FILETYPES[filetype]}) # Ask for a path if path is None. if path.isnone: path = _filedialog_save(return_on_cancellation=return_on_cancellation, behavior_on_cancellation=behavior_on_cancellation, **kwargs) # Check type of path. if not isinstance(path, str): messagebox.showwarning(title='Python type error!', message="The path passed to the function is not a string." "Consider to take a look at the Python code! " "Path has to be set manually.") path = _filedialog_save(return_on_cancellation=return_on_cancellation, behavior_on_cancellation=behavior_on_cancellation, **kwargs) # Check file directory file_dir = path.dirname if not file_dir.isdir and not path.isnone: if auto_mkdir: try: file_dir.makedir() except (FileNotFoundError, PermissionError) as err: logger.exception(err) messagebox.showwarning(title='Error while trying to create a directory!', message="The directory {} doesn't exist and can't be created. " "Please select another directory.".format(file_dir)) path = _filedialog_save(return_on_cancellation=return_on_cancellation, behavior_on_cancellation=behavior_on_cancellation, **kwargs) else: messagebox.showwarning(title='Error while trying to access a directory!', message="The directory {} doesn't exist. " "Please select another directory.".format(file_dir)) path = _filedialog_save(return_on_cancellation=return_on_cancellation, behavior_on_cancellation=behavior_on_cancellation, **kwargs) # Add extension n_path = add_file_extension(path, extension=extension, keep_existing=False, replace=replace_ext) # Check existing file if n_path.isfile: n_path = _handle_existing_file_conflict(n_path, overwrite=overwrite, return_on_cancellation=return_on_cancellation, behavior_on_cancellation=behavior_on_cancellation, auto_mkdir=auto_mkdir, extension=extension, backup=backup, **kwargs) if config_dict and n_path.isfile: # save path in config dict config_dict[config_key] = n_path return n_path
def start_student_reg(bot, message, storage): chat_id = message.message.chat.id message_id = message.message.message_id data = message.data # После того как пользователь выбрал институт if 'institute' in data: data = json.loads(data) courses = storage.get_courses(data['institute']) storage.save_or_update_user( chat_id=chat_id, institute=data['institute'] ) # Записываем в базу институт пользователя try: # Выводим сообщение со списком курсов bot.edit_message_text( message_id=message_id, chat_id=chat_id, text=f'Выберите курс', reply_markup=keyboards.make_inline_keyboard_choose_courses( courses)) except Exception as e: logger.exception(e) return # После того как пользователь выбрал курс или нажал кнопку назад при выборе курса elif 'course' in data: data = json.loads(data) # Если нажали кнопку назад if data['course'] == 'back': storage.delete_user_or_userdata( chat_id=chat_id ) # Удаляем информацию об институте пользователя из базы данных try: bot.edit_message_text(message_id=message_id, chat_id=chat_id, text='Выберите институт', reply_markup=keyboards. make_inline_keyboard_choose_institute( storage.get_institutes())) return except Exception as e: logger.exception(e) return storage.save_or_update_user( chat_id=chat_id, course=data['course']) # Записываем в базу курс пользователя user = storage.get_user(chat_id=chat_id) try: institute = user['institute'] course = user['course'] groups = storage.get_groups(institute=institute, course=course) # Выводим сообщение со списком групп bot.edit_message_text( message_id=message_id, chat_id=chat_id, text=f'Выберите группу', reply_markup=keyboards.make_inline_keyboard_choose_groups( groups)) except Exception as e: logger.exception(e) return # После того как пользователь выбрал группу или нажал кнопку назад при выборе группы elif 'group' in data: data = json.loads(data) # Если нажали кнопку назад if data['group'] == 'back': # Удаляем информацию о курсе пользователя из базы данных storage.delete_user_or_userdata(chat_id=chat_id, delete_only_course=True) try: institute = storage.get_user(chat_id=chat_id)['institute'] except Exception as e: logger.exception(e) return courses = storage.get_courses(institute=institute) try: # Выводим сообщение со списком курсов bot.edit_message_text( message_id=message_id, chat_id=chat_id, text=f'Выберите курс', reply_markup=keyboards.make_inline_keyboard_choose_courses( courses)) return except Exception as e: logger.exception(e) return storage.save_or_update_user( chat_id=chat_id, group=data['group']) # Записываем в базу группу пользователя try: # Удаляем меню регистрации bot.delete_message(message_id=message_id, chat_id=chat_id) except Exception as e: logger.exception(e) return bot.send_message( chat_id=chat_id, text= "Приветствую Вас, Пользователь! Вы успешно зарегистрировались!😊 \n\n" "Я чат-бот для просмотра расписания занятий в Иркутском Политехе.🤖\n\n" "С помощью меня можно не только смотреть свое расписание на день или неделю, но и осуществлять поиск расписания по группам, аудиториям и преподавателям (кнопка [Поиск]).\n" "А еще можно настроить уведомления о парах (в разделе [Другое] кнопка [Напоминания]).\n\n" "Следующие советы помогут раскрыть мой функционал на 💯 процентов:\n" "⏭Используйте кнопки, так я буду Вас лучше понимать!\n\n" "🌄Подгружайте расписание утром и оно будет в нашем чате до скончания времен!\n\n" "📃Чтобы просмотреть список доступных команд и кнопок, напишите в чате [Помощь]\n\n" "🆘Чтобы вызвать эту подсказку снова, напиши в чат [Подсказка] \n\n" "Надеюсь, что Вам будет удобно меня использовать. Для того чтобы пройти регистрацию повторно, напишите сообщение [Регистрация]\n\n" "Если Вы столкнетесь с технической проблемой, то Вы можете:\n" "- обратиться за помощью в официальную группу ВКонтакте [https://vk.com/smartschedule]\n" "- написать одному из моих создателей (команда Авторы)🤭\n", reply_markup=keyboards.make_keyboard_start_menu())
test_lib = 'pptx' import pptx logger.debug(_msg_ptrn.format(test_lib)) test_lib = 'all libraries ok' except ImportError as err: logger.error( "Error while trying to import Python modules! Failed to import '{}'.". format(test_lib)) logger.error(err) if 'DLL load failed' in str(err): logger.error( "Error may be linked to Anaconda distribution.\n" "Try to use pip instead of conda to install modules or use a virtualenv" ) logger.exception(err) print("Opening Python debugger...") pdb.set_trace() __version__ = '1.3.0' __description__ = "Main tools" __icon__ = '\n' __help__ = r"""{} v {} ======= HELP! ======= There is nothing here for the moment! Edit __init__.py file in tools/ directory to add information.
def debugger(): try: logger.debug("Starting Python debugger...") pdb.set_trace() except Exception as err: logger.exception(err)