PyQt 프로젝트 기본 구조

139341 단어 pyqt
PyQt 프로젝트 구조
  • 프로젝트 소개
  • 프로그램 디렉터리 구조
  • config 패키지
  • setting.py
  • 추가 구성 파일
  • deorator 키트
  • lazy_porperty.py
  • utils 패키지
  • logger.py
  • thread.py
  • resourceLoad.py
  • fileutils.py(프로젝트 예)
  • 프레임 팩
  • dialog.py
  • bar.py
  • activity 패키지
  • baseActivity.py
  • main.py
  • requirement.txt
  • 결어
  • 프로젝트 소개
    tags:[pyqt, 파일 관리자, 파일 드래그, 창 스트레칭] 클래스 파일 관리자
    프로그램 디렉토리 구조
    --
      |--- activity  #     
      |--- frame     #     
      |--- config    #     
      |--- utils     #    
      |--- deorator  #    
      |--- resource  #     
    -main.py
    -requirement.txt
    
    

    아래의 질서는 가방의 상간 정도에 따라 순서를 정한다.
    config 패키지
    config 패키지는 배치에서 변경될 수 있는 기본 설정입니다. 예를 들어 데이터베이스, 저장 경로, 상용 문자열 및 기타 서비스의 명령 파라미터 등입니다.
    setting.py
    다음은 샘플 파일일 뿐 실제 프로덕션 파일은 아닙니다.
    import os
    
    dir_path = os.path.abspath(os.path.dirname(__file__))
    ROOT_PATH = os.path.abspath(os.path.join(dir_path, os.path.pardir))
    
    DOC_PATH = os.path.abspath(os.path.join(ROOT_PATH, "doc"))
    
    #       chm  
    temp_path = "temp"
    #   chm  
    chm_path = "document"
    #          
    html_height_line = "html"
    
    
    # crate dir
    
    def check(path):
        if not os.path.exists(path):
            os.makedirs(path)
        return path
    
    
    # document path
    
    def get_chm_path():
        return check(os.path.join(ROOT_PATH, "chm"))
    

    이 파일은 항목에 사용되는 기본 경로를 저장합니다.코드에서 여러 번 사용할 수 있습니다. 예를 들어 후기에 수정할 때 다른 코드가 완전하고 변경할 필요가 없는 기초 위에서 수요를 신속하게 완성할 수 있습니다.
    기타 구성 파일
    프로젝트에 대량의 프로필이 존재하면 여러 종류의 프로필을 새로 만들 수 있습니다.
    deorator 패키지
    이 패키지는 레이지 같은 일반적인 장식기를 저장하고 데이터베이스에 log 봉인할 수 있습니다
    lazy_porperty.py
    lazy 불러오기, lazy에 대한 다른 블로그 설명을 참고할 수 있습니다. 다음 예는 Django2를 사용합니다.3의 lazy 소스
    from functools import total_ordering, wraps
    
    
    # author by Django
    
    class Promise:
        """
                          。
                   。
        """
        pass
    
        def __cast(self):
            pass
    
    
    def _lazy_proxy_unpickle(func, args, kwargs, *result_classes):
        return lazy(func, *result_classes)(*args, **kwargs)
    
    
    def lazy(func, *result_classes):
        """
                           。      
            ——      ,      
                 。           
        """
    
        @total_ordering
        class Proxy(Promise):
            """
                          
                    。      
                         。
            """
            __prepared = False
    
            def __init__(self, args, kw):
                self.__args = args
                self.__kw = kw
                if not self.__prepared:
                    self.__prepare_class__()
                self.__prepared = True
    
            def __reduce__(self):
                return (
                    _lazy_proxy_unpickle,
                    (func, self.__args, self.__kw) + result_classes
                )
    
            def __repr__(self):
                return repr(self.__cast())
    
            @classmethod
            def __prepare_class__(cls):
                for resultclass in result_classes:
                    for type_ in resultclass.mro():
                        for method_name in type_.__dict__:
                            #    __promise__           
                            if hasattr(cls, method_name):
                                continue
                            math = cls.__promise__(method_name)
                            setattr(cls, method_name, math)
                cls._delegate_bytes = bytes in result_classes
                cls._delegate_text = str in result_classes
                assert not (cls._delegate_bytes and cls._delegate_text), (
                    "                 lazy()")
                if cls._delegate_text:
                    cls.__str__ = cls.__text_cast
                elif cls._delegate_bytes:
                    cls.__bytes__ = cls.__bytes_cast
    
            @classmethod
            def __promise__(cls, method_name):
                def __wrapper(self, *args, **kw):
                    res = func(*self.__args, **self.__kw)
                    return getattr(res, method_name)(*args, **kw)
    
                return __wrapper
    
            def __text_cast(self):
                return func(*self.__args, **self.__kw)
    
            def __bytes_cast(self):
                return bytes(func(*self.__args, **self.__kw))
    
            def __bytes_cast_encoded(self):
                return func(*self.__args, **self.__kw).encode()
    
            def __cast(self):
                if self._delegate_bytes:
                    return self.__bytes_cast()
                elif self._delegate_text:
                    return self.__text_cast()
                else:
                    return func(*self.__args, **self.__kw)
    
            def __str__(self):
                # object defines __str__(), so __prepare_class__() won't overload
                # a __str__() method from the proxied class.
                return str(self.__cast())
    
            def __eq__(self, other):
                if isinstance(other, Promise):
                    other = other.__cast()
                return self.__cast() == other
    
            def __lt__(self, other):
                if isinstance(other, Promise):
                    other = other.__cast()
                return self.__cast() < other
    
            def __hash__(self):
                return hash(self.__cast())
    
            def __mod__(self, rhs):
                if self._delegate_text:
                    return str(self) % rhs
                return self.__cast() % rhs
    
            def __deepcopy__(self, memo):
                #              。         。
                memo[id(self)] = self
                return self
    
        @wraps(func)
        def __wrapper__(*args, **kw):
            #       
            return Proxy(args, kw)
    
        return __wrapper__
    
    
    class LazyProperty(object):
        """
        lazy      
                   :
        @LazyProperty
        def test_function():
            do something
        """
        def __init__(self, fun):
            self.fun = fun
    
        def __get__(self, instance, owner):
            if instance is None:
                return self
            value = self.fun(instance)
            setattr(instance, self.fun.__name__, value)
            return value
    
    

    utils 패키지
    도구 패키지에는 문자열 처리, 파일 처리, 루틴 조작, 로그 등 자주 사용하는 도구 종류가 저장되어 있습니다.
    logger.py
    python logging 로그 패키지는 실제 요구를 직접적으로 충족시키지 못하기 때문에 logger를 재구성해야 합니다 (예시 파일에서 setting의 로그를 포함하는 저장 경로 setting.get log path () 를 제외하고는 독립적으로 실행할 수 있습니다)
    # coding=utf-8
    """
        create by pymu on 2020/4/29
        package: .logger.py
        project: status_document_0.1
    """
    import datetime
    import logging
    import os
    import re
    
    from config import setting
    
    description = "    "
    LOG_PATH = setting.get_log_path()
    
    
    class Logger(logging.Logger):
        """
    
        """
    
        def __init__(self, name='system', level=logging.INFO):
            super().__init__(name, level)
            self.level = level
            self.name = name
            self.__set_log_handler()
    
        def __set_log_handler(self):
            """
                       ,   INFO
            :return:
            """
            main_handler = MyLoggerHandler(filename=self.name, when='D', backup_count=5,
                                           encoding="utf-8")
            warn_handler = MyLoggerHandler(filename='    ', when='D',
                                           backup_count=5, encoding="utf-8")
            error_handler = MyLoggerHandler(filename='    ', when='D',
                                            backup_count=35, encoding="utf-8")
            #       
            formatter = logging.Formatter("%(asctime)s - %(levelname)s: %(message)s")
            _formatter = logging.Formatter("
    %(asctime)s - %(levelname)s: %(message)s"
    ) bug_filter = logging.Filter() bug_filter.filter = lambda record: record.levelno == logging.ERROR # error_handler.addFilter(bug_filter) error_handler.setFormatter(_formatter) self.addHandler(error_handler) bug_filter = logging.Filter() bug_filter.filter = lambda record: record.levelno == logging.WARNING # warn_handler.addFilter(bug_filter) warn_handler.setFormatter(_formatter) self.addHandler(warn_handler) bug_filter = logging.Filter() bug_filter.filter = lambda record: record.levelno < logging.WARNING # main_handler.addFilter(bug_filter) main_handler.addFilter(bug_filter) main_handler.setFormatter(formatter) self.main_handler = main_handler self.addHandler(main_handler) def reset_name(self, name): """ :param name: :return: """ self.name = name self.removeHandler(self.main_handler) self.__set_log_handler() try: import codecs except ImportError: codecs = None class MyLoggerHandler(logging.FileHandler): def __init__(self, filename, when='M', backup_count=15, encoding=None, delay=False): self.prefix = os.path.join(LOG_PATH, '{name}'.format(name=filename)) self.filename = filename self.when = when.upper() # S - Every second a new file # M - Every minute a new file # H - Every hour a new file # D - Every day a new file if self.when == 'S': self.suffix = "%Y-%m-%d_%H-%M-%S" self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\.log$" elif self.when == 'M': self.suffix = "%Y-%m-%d_%H-%M" self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.log$" elif self.when == 'H': self.suffix = "%Y-%m-%d_%H" self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}\.log$" elif self.when == 'D': self.suffix = "%Y-%m-%d" self.extMatch = r"^\d{4}-\d{2}-\d{2}$" else: raise ValueError("Invalid rollover interval specified: %s" % self.when) self.filePath = "%s%s.log" % (self.prefix, datetime.datetime.now().strftime(self.suffix)) try: if os.path.exists(LOG_PATH) is False: os.makedirs(LOG_PATH) except Exception as e: print("can not make dirs") print("filepath is " + self.filePath) print(e) self.backupCount = backup_count if codecs is None: encoding = None logging.FileHandler.__init__(self, self.filePath, 'a', encoding, delay) def write_log(self): _filePath = "%s%s.log" % (self.prefix, datetime.datetime.now().strftime(self.suffix)) if _filePath != self.filePath: self.filePath = _filePath return 1 return 0 def change_file(self): self.baseFilename = os.path.abspath(self.filePath) if self.stream is not None: self.stream.flush() self.stream.close() if not self.delay: self.stream = self._open() if self.backupCount > 0: for s in self.delete_old_log(): os.remove(s) def delete_old_log(self): dir_name, base_name = os.path.split(self.baseFilename) file_names = os.listdir(dir_name) result = [] p_len = len(self.filename) for fileName in file_names: if fileName[:p_len] == self.filename: suffix = fileName[p_len:] if re.compile(self.extMatch).match(suffix): result.append(os.path.join(dir_name, fileName)) result.sort() if len(result) < self.backupCount: result = [] else: result = result[:len(result) - self.backupCount] return result def emit(self, record): """ Emit a record. """ # noinspection PyBroadException try: if self.write_log(): self.change_file() logging.FileHandler.emit(self, record) except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record) if __name__ == "__main__": # to do something log = Logger('info') import time for i in range(12): time.sleep(1) log.info(" " + str(i))

    특히 로그는 창의 기본 클래스에서 설명할 수 있습니다. 그러면 하위 클래스에서 호출할 수 있습니다. 구체적인 로그 성명은 제출 로그 방법으로 표시하거나 로그 방법에서 추출하는 방법 이름으로 표시됩니다.
    thread.py
    qt에서는 데이터를 다른 단계로 업데이트하거나 실행하기 위해 라인을 사용합니다.UI 스레드가 혼잡하지 않도록 하기 위해서는 Qthread가 시간 소모 방법을 실행해야 하며,thread 방법으로 인터페이스를 직접 업데이트하면 신호가 없는 스레드가 UI를 업데이트할 것을 경고합니다.
    #!/usr/bin/python3
    # coding=utf-8
    
    
    """---------------------------------------
    
            project :    
              /   :.thread.py
                   :v1.0
                   :pymu on 2020/4/22
            
               :
    
    ---------------------------------------"""
    from PyQt5.QtCore import QThread, pyqtSignal
    
    from utils.logger import Logger
    
    
    class FuncThread(QThread):
        """
              
        """
        #       
        thread_signal = pyqtSignal(dict)
        #       
        thread_error_signal = pyqtSignal(str)
    
        def __init__(self):
            super().__init__()
            self.func = None
            self.func_args = []
            self.func_kwargs = {}
            self.logger = Logger()
    
        def set_func(self, func, *args, **kwargs):
            """
                  ,            ,                   
                  
            :param func:       
            :param args:        
            :param kwargs:       (   )
            :return:  None
            """
            self.func = func
            self.func_args = args
            self.func_kwargs = kwargs
            self.logger.info("     func={}  arg={}  kwargs={}".format(func.__name__, args, kwargs))
    
        def run(self):
            """
                :
              start()    
                    ,         
            """
            if not self.func:
                return
            self.logger.info("   func={}  arg={}  kwargs={}".format(self.func.__name__, self.func_args, self.func_kwargs))
            try:
                result = self.func(*self.func_args, **self.func_kwargs)
                if not isinstance(result, dict):
                    result = {}
                self.thread_signal.emit(result)
            except Exception as e:
                self.thread_error_signal.emit(str(e))
                self.logger.error("     func={}  arg={}  kwargs={}, error={}".format(self.func.__name__,
                                                                                     self.func_args,
                                                                                     self.func_kwargs,
                                                                                     e))
    
    

    참고: 메소드에 추가될 수 있습니다. 실행 성공 신호, 예외 신호를 제외하고 여러 개의 신호를 추가할 수 있지만 실행 방법에 제출 신호(관찰자 모드)를 명시해야 합니다. 구체적인 사용 방법은 다음에 실례적으로 설명합니다. #스레드self를 업데이트합니다.update_thread = FuncThread() self.update_thread.thread_signal.connect(self.set_tree_data) self.update_thread.set_func(self.get_dir_dict, self.activity_path, _) self.update_thread.start()
    resourceLoad.py
    정적 자원 마운트, qt에서 대량의 아이콘 파일, 글꼴 설명을 사용합니다.(qt가 메모리에 저장될지 모르기 때문에 스스로 추가했다) 레이지 불러오기와 결합하면 빠르게 접근할 수 있다(복잡한 레이아웃에 대한).
    #!/usr/bin/python3
    # coding=utf-8
    
    
    """---------------------------------------
    
            project :    
              /   :.resourceLoad.py
                   :v1.0
                   :pymu on 2020/4/21
            
               :          
    
    ---------------------------------------"""
    import os
    import threading
    
    import qtawesome
    from PyQt5 import QtGui
    from PyQt5.QtCore import Qt
    from PyQt5.QtGui import QFont, QBrush, QColor
    
    from config import setting
    from utils.lazy_property import LazyProperty
    
    
    class Resource:
        """
              
        """
        _instance_lock = threading.Lock()
    
        def __init__(self):
            self.img_path = setting.get_img_path()
    
        @classmethod
        def instance(cls):
            with Resource._instance_lock:
                if not hasattr(Resource, "_instance"):
                    Resource._instance = Resource()
            return Resource._instance
    
        def render_icon(self, name):
            """
              
            :return:
            """
            path = os.path.join(self.img_path, name)
            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap(path), QtGui.QIcon.Normal, QtGui.QIcon.On)
            return icon
    
        @LazyProperty
        def QT_img_document(self):
            """
                 
            :return:
            """
            return self.render_icon("icon_tree_document.png")
    
        @LazyProperty
        def QT_img_dir(self):
            """
                  
            :return:
            """
            return self.render_icon("icon_tree_file.png")
    
        @LazyProperty
        def QT_img_doc(self):
            """
            doc   
            :return:
            """
            return self.render_icon("icon-word.png")
    
        @LazyProperty
        def QT_img_excel(self):
            """
            Excel   
            :return:
            """
            return self.render_icon("icon-excel.png")
    
        @LazyProperty
        def QT_img_pdf(self):
            """
            PDF   
            :return:
            """
            return self.render_icon("icon-pdf.png")
    
        @LazyProperty
        def QT_img_template_logo(self):
            """
                logo   
            :return:
            """
            return self.render_icon("logo-document.png")
    
        @LazyProperty
        def QT_img_new_folder(self):
            """
                    
            :return:
            """
            return self.render_icon("icon-add.png")
    
        @LazyProperty
        def QT_img_delete(self):
            """
                 
            :return:
            """
            return self.render_icon("icon-delete.png")
    
        @LazyProperty
        def QT_img_upload(self):
            """
                 
            :return:
            """
            return self.render_icon("icon-up.png")
    
        @LazyProperty
        def QT_img_download(self):
            """
                 
            :return:
            """
            return self.render_icon("icon-down.png")
    
        @LazyProperty
        def QT_img_search(self):
            """
                 
            :return:
            """
            return self.render_icon("icon_search.png")
    
        @LazyProperty
        def QT_img_home_logo(self):
            """
    
                 
            :return:
            """
            return self.render_icon("icon-catalogue.png")
    
        @LazyProperty
        def QT_img_clear(self):
            """
                 
            :return:
            """
            return self.render_icon("icon_input_clear.png")
    
        @LazyProperty
        def QT_img_unknown(self):
            """
                   
            :return:
            """
            return self.render_icon("unknown.png")
    
        @LazyProperty
        def QT_img_none(self):
            """
               
            :return:
            """
            return self.render_icon("??")
    
        @LazyProperty
        def QT_img_input_user(self):
            """
                
            :return:
            """
            # return self.render_icon("icon_login_user.png")
            return qtawesome.icon('fa.user', color="#666")
    
        @LazyProperty
        def QT_img_input_pass(self):
            """
                
            :return:
            """
            # return self.render_icon("icon_login_key.png")
            return qtawesome.icon('fa.unlock-alt', color="#666")
    
        @LazyProperty
        def QT_img_user_more(self):
            """
              
            :return:
            """
            return qtawesome.icon('fa.angle-down', color="white")
    
        @LazyProperty
        def QT_font_16px_song(self):
            """
            14 px
              
            :return:
            """
            font = QFont()
            font.setPixelSize(16)
            font.setFamily("  ")
            return font
    
        @LazyProperty
        def QT_brush_font_color_333(self):
            """
                   1
            :return:
            """
            brush = QBrush(QColor(51, 51, 51, 255))
            brush.setStyle(Qt.NoBrush)
            return brush
    

    fileutils.py(프로젝트 예)
    이것은 내 프로젝트에서 가장 짜증나는 부분, 불필요하고 질질 끄는 부분을 저장하여 사용할 수 있다.
    #!/usr/bin/python3
    # coding=utf-8
    
    
    """---------------------------------------
    
            project :    
              /   :.fileutils.py
                   :v1.0
                   :pymu on 2020/4/13
    
               :       
    
    ---------------------------------------"""
    import base64
    import json
    import os
    import shutil
    import time
    from lxml import etree
    
    from config import setting
    
    
    def get_file_name(path):
        file_name = os.path.basename(path)
        if not file_name:
            return
        else:
            return file_name.split(".")[0]
    
    
    def unchm(path):
        """
          chm          
        :param path:
        :return:
        """
        file_name = get_file_name(path)
        if not file_name:
            return
        temp_path = os.path.join(setting.get_temp_path(), file_name)
        if not os.path.exists(temp_path):
            os.makedirs(temp_path)
        command = "HH.EXE -decompile {export_path} {source_path}".format(export_path=temp_path, source_path=path)
        os.system(command)
    
    
    def formatTime(temp_time):
        """
        '''        '''
        :param temp_time:
        :return:
        """
        return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(temp_time))
    
    
    def formatByte(number):
        """
               
        :param number:
        :return:
        """
        if number < 1024:
            return "  1  "
        elif number <= 1024 * 1024:
            return "%.2f KB" % (number / 1024.0)
        elif number <= (1024 * 1024 * 1024):
            return "%.2f MB" % (number / 1024.0 / 1024.0)
        elif number <= (1024 * 1024 * 1024 * 1024):
            return "%.2f GB" % (number / 1024.0 / 1024.0 / 1024.0)
        else:
            return "      "
    
    
    def get_doc_dict(path, match_html=True):
        """
              ,        
        :return:
        """
        result = dict()
        if not os.path.exists(path):
            return result
    
        for i in os.listdir(path):
            file = os.path.join(path, i)
            if os.path.isdir(file):
                s = get_doc_dict(file)
                if s:
                    result.update({i: s})
            else:
                f_type = i.split(".")
                if match_html:
                    if len(f_type) > 0 and "html" in f_type[-1] or "htm" in f_type[-1]:
                        result.update({i: file})
                else:
                    result.update({i: file})
        return None if len(result.keys()) == 0 else result
    
    
    def get_doc_dict_new(path):
        """
                   
        :param path:
        :return:
        """
        result = dict()
        if not os.path.exists(path):
            return result
    
        for i in os.listdir(path):
            file = os.path.join(path, i)
            if os.path.isdir(file):
                s = get_doc_dict_new(file)
                result.update({i: s})
            else:
                result.update({i: file})
        return result
    
    
    def get_dir_dict(path):
        """
            ,          
        :param path:
        :return:
        """
        result = dict()
        if not os.path.exists(path):
            return result
    
        for i in os.listdir(path):
            file = os.path.join(path, i)
            if os.path.isdir(file):
                s = get_dir_dict(file)
                result.update({i: s})
        return result
    
    
    def get_path_list(path, root_path):
        """
                             
        :param root_path:       ,        
        :param path:   path    
        :return:
        """
        result_dict = dict()
        result_dict.update({"root": path})
        result = list()
        for root, dirs, files in os.walk(path):
            for dir_t in dirs:
                item = dict()
                path = os.path.join(root, dir_t)
                item.update({
                    "last_change_time": formatTime(os.path.getctime(path)),
                    "path": path,
                    "size": "",
                    "name": dir_t,
                    "type": "dir"
                })
                result.append(item)
    
            for file in files:
                item = dict()
                path = os.path.join(root, file)
                file_info = os.stat(path)
                item.update({"path": os.path.abspath(path),
                             "size": formatByte(os.path.getsize(path)),
                             "last_change_time": formatTime(file_info.st_mtime),
                             "name": file,
                             "type": os.path.splitext(path)[1]})
                result.append(item)
            if not result:
                result.insert(0, {"path": os.path.abspath(os.path.join(root, os.path.pardir)),
                                  "size": "",
                                  "last_change_time": "",
                                  "name": "    ",
                                  "type": "none"})
            if not root == root_path:
                result.insert(0, {"path": os.path.abspath(os.path.join(root, os.path.pardir)),
                                  "size": "",
                                  "last_change_time": "",
                                  "name": "<,
                                  "type": "back"})
            break
        result_dict.update({"data": result})
        return result_dict
    
    
    def clean_temp_file(paths: list):
        """
                 
        :param paths:
        :return:
        """
        for file in os.listdir(setting.get_temp_path()):
            file_path = os.path.join(setting.get_temp_path(), file)
            if file_path not in paths:
                print(file_path)
                # noinspection PyBroadException
                try:
                    shutil.rmtree(file_path)
                except Exception as e:
                    print(e)
    
    
    def check_chm():
        """
              chm  
                
        :return:
        """
        file_dir = []
        for file in os.listdir(setting.get_chm_path()):
            #      
            file_path = os.path.join(setting.get_chm_path(), file)
            if os.path.isfile(file_path):
                s = file.split(".")
                if len(s) > 1 and str(s[-1]).lower() == "chm":
                    file_name = get_file_name(file_path)
                    if not file_name:
                        return
                    temp_path = os.path.join(setting.get_temp_path(), file_name)
                    file_dir.append(temp_path)
                    if not os.path.exists(temp_path):
                        unchm(file_path)
        clean_temp_file(file_dir)
    
    
    def match_key(path, key) -> bool:
        """
                  
        :param path:
        :param key:
        :return:
        """
        # noinspection PyBroadException
        try:
            with open(path, "rb") as f:
                response = etree.HTML(text=f.read())
                if key in response.xpath('string(.)'):
                    return True
                return False
        except:
            return False
    
    
    def test():
        from lxml import etree
        with open("temp/css/index.htm", "rb") as f:
            response = etree.HTML(text=f.read())
            if "    1" in response.xpath('string(.)'):
                return True
            return False
    
    
    def make_dir(path, name):
        """
             
        :param name:
        :param path:
        :return:
        """
        path = os.path.join(path, name)
        os.makedirs(path)
    
    
    def filter_search(result: dict, data, m):
        """
                            key    list
        :param result:
        :param data:
        :param m:
        :return:
        """
        if isinstance(data, dict):
            # key      , value     
            for key in data:
                value = data.get(key)
                #          
                if isinstance(value, dict):
                    filter_search(result, value, m)
                else:
                    if m.lower() in key.lower():
                        item = {"path": value,
                                "size": "",
                                "last_change_time": "",
                                "name": key,
                                "type": os.path.splitext(str(value))[1]}
                        result.get("data").append(item)
    
    
    def delete_any(path):
        """
               
        """
        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)
    
    
    def delete_path(path):
        """
                    ,       ,          
        :param path:
        :return:
        """
        if isinstance(path, list):
            for i in path:
                delete_any(i)
            return
        if isinstance(path, str):
            delete_any(path)
            return
        raise Exception("        {}".format(path))
    
    
    def check_exists(source, target):
        """
                
        :param source:
        :param target:
        :return:
        """
        result = []
        if source:
            for i in source:
                file_name = os.path.basename(i)
                if os.path.exists(os.path.join(target, file_name)):
                    result.append(file_name)
        return result
    
    
    def copy_file(source, target):
        """
            
        :param target:
        :param source:
        :return:
        """
        if source:
            target = os.path.abspath(target)
            for i in source:
                target_ = os.path.join(target, os.path.basename(i))
                if os.path.isfile(i):
                    shutil.copyfile(i, target_)
                else:
                    if os.path.exists(target_):
                        shutil.rmtree(target_)
                    shutil.copytree(i, target_)
    
    
    def get_load_user_info():
        """
                 
        :return:
        """
        # noinspection PyBroadException
        try:
            with open(setting.get_user_ini_path(), "rb") as f:
                content = f.read()
            return json.loads(base64.b64decode(content).decode())
        except Exception as e:
            print(e)
            return dict()
    
    
    # noinspection PyBroadException
    def replace_html(path, key):
        """
                  
        :param key:
        :param path:
        :return:
        """
        if not path:
            return
        path = os.path.join(setting.get_activity_path(), path)
        if key:
            resource_path = setting.get_resource_path()
            html_path = os.path.join(resource_path, "html")
            html_path = os.path.join(html_path, "temp.html")
            js_path = os.path.join(resource_path, "js")
    
            # jq     
            jq_path = os.path.join(js_path, "jquery-1.12.4.min.js")
    
            # js     
            js_path = os.path.join(js_path, "height_line._js")
    
            #      ,       
            with open(path, "r", errors='ignore') as file:
                html_content = file.read()
            #         js
            with open(js_path, "r", errors='ignore') as file:
                js_content = file.read()
    
            #     
            if html_content and js_content:
                js_content = js_content.replace("{{key}}", key)
                js_content = js_content.replace("{{jq_path}}", "file:///" + jq_path.replace("\\", "/"))
                new_content = html_content.replace("

    좋은 웹페이지 즐겨찾기