Пример #1
0
    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
Пример #2
0
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))
Пример #3
0
 def test_out_function(self):
     logger.info("测试数字和元组数字是否相等!!")
     try:
         assert 3 == (4, )
     except AssertionError:
         logger.exception("测试数字和元组数字是否相等失败!!")
         raise
     else:
         logger.info("测试数字和元组数字是否相等通过!!")
Пример #4
0
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
Пример #5
0
 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 通过!!")
Пример #6
0
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
Пример #7
0
 def test_a(self):
     logger.info("测试数字和字符串数字是否相等!")
     try:
         a = 1
         assert 1 is a
         assert 1 == '1'
     except AssertionError:
         logger.exception('测试数字和字符串数字是否相等失败!!')
         raise
     else:
         logger.info("测试数字和字符串是否相等通过!!")
Пример #8
0
 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
Пример #9
0
 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)
Пример #10
0
 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
Пример #11
0
 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))
Пример #12
0
 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
Пример #13
0
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}')
Пример #15
0
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())
Пример #17
0
    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.
Пример #18
0
def debugger():
    try:
        logger.debug("Starting Python debugger...")
        pdb.set_trace()
    except Exception as err:
        logger.exception(err)