def __new__(mcs, name, bases, clsdict): setup_class_dependency_injection(name, clsdict) cls = super().__new__(mcs, name, bases, clsdict) if ABSTRACT_ATTR in clsdict: setattr(cls, NOT_VIEWS_ATTR, get_not_views(clsdict, bases)) setattr( cls, REMOVE_SUFFIXES_ATTR, get_remove_suffixes(name, bases, CONTROLLER_REMOVE_EXTRA_SUFFIXES)) return cls controller_routes = getattr(cls, CONTROLLER_ROUTES_ATTR, {}).copy() not_views = deep_getattr({}, bases, NOT_VIEWS_ATTR) for method_name, method in clsdict.items(): if (method_name in not_views or not is_view_func(method_name, method)): controller_routes.pop(method_name, None) continue method_routes = getattr(method, FN_ROUTES_ATTR, [Route(None, method)]) for route in method_routes: route.blueprint = deep_getattr(clsdict, bases, 'blueprint') route._controller_name = name controller_routes[method_name] = method_routes setattr(cls, CONTROLLER_ROUTES_ATTR, controller_routes) return cls
def __new__(mcs, name, bases, clsdict): if ABSTRACT_ATTR in clsdict: return super().__new__(mcs, name, bases, clsdict) routes = {} include_methods = set(deep_getattr(clsdict, bases, 'include_methods')) exclude_methods = set(deep_getattr(clsdict, bases, 'exclude_methods')) for method_name in ALL_METHODS: if (method_name in exclude_methods or method_name not in include_methods): continue route = getattr(clsdict.get(method_name), FN_ROUTES_ATTR, [None])[0] if not route: route = Route(None, deep_getattr(clsdict, bases, method_name)) route._controller_name = name if method_name in INDEX_METHODS: rule = '/' else: rule = deep_getattr(clsdict, bases, 'member_param') route.rule = rule routes[method_name] = [route] cls = super().__new__(mcs, name, bases, clsdict) if cls.model is None: raise AttributeError(f'{name} is missing the model attribute') setattr(cls, CONTROLLER_ROUTES_ATTR, routes) return cls
def __new__(mcs, name, bases, clsdict): cls = super().__new__(mcs, name, bases, clsdict) if ABSTRACT_ATTR in clsdict: setattr( cls, REMOVE_SUFFIXES_ATTR, get_remove_suffixes(name, bases, RESOURCE_REMOVE_EXTRA_SUFFIXES)) return cls controller_routes = getattr(cls, CONTROLLER_ROUTES_ATTR) for method_name in ALL_METHODS: if not clsdict.get(method_name): continue if method_name in INDEX_METHODS: rule = '/' else: rule = deep_getattr(clsdict, bases, 'member_param') route = controller_routes.get(method_name)[0] route.rule = rule controller_routes[method_name] = [route] setattr(cls, CONTROLLER_ROUTES_ATTR, controller_routes) return cls
def get_not_views(clsdict, bases): not_views = deep_getattr({}, bases, NOT_VIEWS_ATTR, []) return ({ name for name, method in clsdict.items() if is_view_func(name, method) and not getattr(method, FN_ROUTES_ATTR, None) }.union(not_views))
def __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) _model_registry._ensure_correct_base_model(mcs_args) ModelMetaFactoryClass = deep_getattr(clsdict, mcs_args.bases, '_meta_factory_class', ModelMetaFactory) model_meta_factory: ModelMetaFactory = ModelMetaFactoryClass() model_meta_factory._contribute_to_class(mcs_args) if model_meta_factory.abstract: return super().__new__(*mcs_args) validators = deep_getattr(clsdict, mcs_args.bases, '__validators__', defaultdict(list)) columns = { col_name: col for col_name, col in clsdict.items() if isinstance(col, Column) } for col_name, col in columns.items(): if not col.name: col.name = col_name if col.info: for v in col.info.get('validators', []): if v not in validators[col_name]: validators[col_name].append(v) for attr_name, attr in clsdict.items(): validates = getattr(attr, '__validates__', None) if validates and deep_getattr(clsdict, mcs_args.bases, validates): if attr_name not in validators[attr.__validates__]: validators[attr.__validates__].append(attr_name) continue m = VALIDATOR_RE.match(attr_name) column = m.groupdict()['column'] if m else None if m and deep_getattr(clsdict, mcs_args.bases, column, None) is not None: attr.__validates__ = column if attr_name not in validators[column]: validators[column].append(attr_name) clsdict['__validators__'] = validators _model_registry.register_new(mcs_args) return super().__new__(*mcs_args)
def _ensure_correct_base_model(self, mcs_args: McsArgs): if not self._base_model_classes: return correct_base = list(self._base_model_classes.values())[-1] for b in mcs_args.bases: if issubclass(b, correct_base): return mcs_args.clsdict['_meta'] = \ deep_getattr({}, mcs_args.bases, '_meta', None) mcs_args.bases = tuple([correct_base] + list(mcs_args.bases))
def test_deep_getattr(): clsdict = {'a': 'clsdict'} class First: a = 'first' b = 'first' class Second: b = 'second' c = 'second' bases = (First, Second) assert deep_getattr(clsdict, bases, 'a') == 'clsdict' assert deep_getattr(clsdict, bases, 'b') == 'first' assert deep_getattr(clsdict, bases, 'c') == 'second' with pytest.raises(AttributeError): deep_getattr(clsdict, bases, 'd') assert deep_getattr(clsdict, bases, 'a', 'default') == 'clsdict' assert deep_getattr(clsdict, bases, 'b', 'default') == 'first' assert deep_getattr(clsdict, bases, 'c', 'default') == 'second' assert deep_getattr(clsdict, bases, 'd', 'default') == 'default'
def _contribute_to_class(self, mcs_args: McsArgs): self._mcs_args = mcs_args meta = mcs_args.clsdict.pop('Meta', None) base_model_meta = deep_getattr(mcs_args.clsdict, mcs_args.bases, '_meta', None) mcs_args.clsdict['_meta'] = self options = self._get_model_meta_options() if (os.getenv('FLASK_ENV', None) != TEST and not isinstance(options[0], AbstractMetaOption)): raise Exception('The first option in _get_model_meta_options ' 'must be an instance of AbstractMetaOption') self._fill_from_meta(meta, base_model_meta, mcs_args) for option in options: option_value = getattr(self, option.name, None) option.contribute_to_class(mcs_args, option_value)
def __new__(mcs, name, bases, clsdict): setup_class_dependency_injection(name, clsdict) if ABSTRACT_ATTR in clsdict: return super().__new__(mcs, name, bases, clsdict) meta = deep_getattr(clsdict, bases, 'Meta', None) model_missing = False try: if meta.model is None: model_missing = True except AttributeError: model_missing = True if model_missing: raise AttributeError(f'{name} is missing the class ' f'Meta model attribute') elif isinstance(meta.model, str): meta.model = unchained.flask_sqlalchemy_bundle.models[meta.model] clsdict['Meta'] = meta return super().__new__(mcs, name, bases, clsdict)
def _is_base_polymorphic_model(self): if not self.polymorphic: return False base_meta = deep_getattr({}, self._mcs_args.bases, '_meta') return base_meta.abstract
def get_remove_suffixes(name, bases, extras): existing_suffixes = deep_getattr({}, bases, REMOVE_SUFFIXES_ATTR, []) new_suffixes = [name] + extras return ([x for x in new_suffixes if x not in existing_suffixes] + existing_suffixes)