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('.')