import json import re from pathlib import Path from pycs import db from pycs.database.base import NamedBaseModel from pycs.interfaces.LabelProvider import LabelProvider as LabelProviderInterface class LabelProvider(NamedBaseModel): """ DB model for label providers """ description = db.Column(db.String) root_folder = db.Column(db.String, nullable=False) configuration_file = db.Column(db.String, nullable=False) # relationships to other models projects = db.relationship("Project", backref="label_provider", lazy="dynamic") # contraints __table_args__ = ( db.UniqueConstraint('root_folder', 'configuration_file'), ) serialize_only = NamedBaseModel.serialize_only + ( "description", "root_folder", "configuration_file", ) @classmethod def discover(cls, root: Path): """ searches for label providers under the given path and stores them in the database """ for folder, conf_path in _find_files(root): with open(conf_path) as conf_file: config = json.load(conf_file) provider, _ = cls.get_or_create( root_folder=str(folder), configuration_file=conf_path.name ) provider.name = config['name'] # returns None if not present provider.description = config.get('description') provider.flush() db.session.commit() @property def root(self) -> Path: """ returns the root folder as Path object """ return Path(self.root_folder) @property def configuration_file_path(self) -> str: """ return the configuration file as Path object """ return str(self.root / self.configuration_file) def load(self) -> LabelProviderInterface: """ load configuration.json and create an instance from the included code object :return: LabelProvider instance """ # load configuration.json with open(self.configuration_file_path) as configuration_file: configuration = json.load(configuration_file) # load code code_path = str(self.root / configuration['code']['module']) module_name = code_path.replace('/', '.').replace('\\', '.') class_name = configuration['code']['class'] imported_module = __import__(module_name, fromlist=[class_name]) class_attr = getattr(imported_module, class_name) # return instance return class_attr(self.root_folder, configuration) def _find_files(root: str, config_regex=re.compile(r'^configuration(\d+)?\.json$')): """ generator for config files found under the given path """ for folder in Path(root).glob('*'): # list files for file_path in folder.iterdir(): # filter configuration files if not file_path.is_file(): continue if config_regex.match(file_path.name) is None: continue # yield element yield folder, file_path