Source code for sqlbatis.scanner

import os
import re
import inspect
import importlib
from sqlbatis.model import Model


[docs]class Scanner: """ The basic scanner to search the files in specific folder. """ def __init__(self, directory, exclude, file_type): """The initialization of the scanner :param directory: the main folder that want to search. :type directory: string :param exclude: this should be a regrex expression list, will do the exclude the file or folder according to the exclude rules. :type exclude: list, optional :param file_type: the suffix of the file, it defines the file type that you want to search in the directory. :type file_type: str, optional """ self.directory = directory self.file_type = file_type self.exclude = exclude def _get_files_by_type(self, directory=None): """Retrieve all the files that according to the rules as below: 1. file is contained in the directory 2. the file or folder name is not match with regrex experssion in the exclude list 3. endswith the file type that user defined :param directory: the directory that you want to find the file, defaults to None :type directory: string, optional :return: all matched files path :rtype: list of the string """ # the results list to contain the file path files_path = [] # if not directory was given, use the directory that the user specified if not directory: directory = self.directory files = os.listdir(directory) for file in files: # if the file or folder name match with the regrex if_exluded = [re.search(pattern, file) for pattern in self.exclude] if not any(if_exluded): file = os.path.join(directory, file) if os.path.isfile(file) and file.endswith(self.file_type): files_path.append(file) elif os.path.isdir(file): # recursive to call the func sub_files_path = self._get_files_by_type(file) files_path.extend(sub_files_path) else: pass return files_path
[docs]class ModelScanner(Scanner): def __init__(self, directory='.', exclude=[]): """The scanner for search all the model classes in the project, and will return all the class which inherit the sqlbatis [Model] class :param directory: the main folder that want to search, defaults to '.' :type directory: str, optional :param exclude: exlude regression, same as scanner, defaults to [] :type exclude: list, optional """ super(ModelScanner, self).__init__(directory, exclude, '.py') # FIXME: # exlude the setup.py when we try to find the py files, it will give a error that # dynamic import the module self.exclude.append('setup.py') self.models = {}
[docs] def scan_models(self): """Scan all the sqlbatis models in the folder that user specified :return: SQLBatis models list :rtype: list """ files = self._get_files_by_type() # if abspath is provided, will convert it to the relative path so we can # dynamic import the module relative_files = self._convert_to_relative_path(files) for file in relative_files: _module = '.'.join(file.split(os.sep)[1:]) _models = self._get_model_class_in_the_module(_module) self.models.update(_models) return list(self.models.values())
def _get_model_class_in_the_module(self, path): """Instaniate an module and find all the classes in the module, and then check if the SQLBatis's [Model] or not, if yes, will added to models list and return :param path: The import path of the module :type path: str :return: SQLBatis Models :rtype: list """ sqlbatis_models = {} # discard the suffix of the file module, _ = path.rsplit('.', maxsplit=1) module_instance = importlib.import_module(module) for name, obj in inspect.getmembers(module_instance): if inspect.isclass(obj) and issubclass(obj, Model): # abandon the orginal Model class defined in the SQLBatis if not obj.__name__ == 'Model': sqlbatis_models[name] = obj return sqlbatis_models def _convert_to_relative_path(self, files_path): """Convert the abspath to the relative path :param files_path: all the files path's string, it may contain the relative path, we will process the abspath only :type files_path: list[str] :return: all the files relative path :rtype: list[str] """ relative_files_path = [] current_work_dir = os.getcwd() for file_path in files_path: # if file path is abspath, will replace the current work dir string with '.' if file_path.startswith('/'): _file_path = file_path.replace(current_work_dir, '.') else: _file_path = file_path relative_files_path.append(_file_path) return relative_files_path
if __name__ == "__main__": scanner = ModelScanner('.')