예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
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))
예제 #5
0
    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)
예제 #6
0
    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))
예제 #7
0
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'
예제 #8
0
    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)
예제 #9
0
    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)
예제 #10
0
 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
예제 #11
0
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)