def _get_remove_suffixes(name, bases, extras): existing_suffixes = deep_getattr({}, bases, REMOVE_SUFFIXES_ATTR, []) new_suffixes = [name] + extras return ( [suffix for suffix in new_suffixes if suffix not in existing_suffixes] + existing_suffixes)
def __new__(mcs, name, bases, clsdict): if (ABSTRACT_ATTR in clsdict or getattr(clsdict.get('Meta', object), 'abstract', False)): return super().__new__(mcs, name, bases, clsdict) cls = super().__new__(mcs, name, bases, clsdict) routes = {} include_methods = set(cls.Meta.include_methods) exclude_methods = set(cls.Meta.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)) if method_name in INDEX_METHODS: rule = '/' else: rule = cls.Meta.member_param route.rule = rule routes[method_name] = [route] setattr(cls, CONTROLLER_ROUTES_ATTR, routes) return cls
def __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) set_up_class_dependency_injection(mcs_args) if clsdict.get('__abstract__', getattr(clsdict.get('Meta'), 'abstract', False)): mcs_args.clsdict[REMOVE_SUFFIXES_ATTR] = _get_remove_suffixes( name, bases, CONTROLLER_REMOVE_EXTRA_SUFFIXES) mcs_args.clsdict[NOT_VIEWS_ATTR] = _get_not_views(clsdict, bases) apply_factory_meta_options( mcs_args, default_factory_class=ControllerMetaOptionsFactory) cls = super().__new__(*mcs_args) if mcs_args.Meta.abstract: 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 controller_routes[method_name] = getattr(method, FN_ROUTES_ATTR, [Route(None, method)]) 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) set_up_class_dependency_injection(mcs_args) 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') else: try: meta.model = unchained.sqlalchemy_bundle.models[ meta.model.__name__] except AttributeError: # this happens when attempting to generate documentation and the # sqlalchemy bundle hasn't been loaded pass except KeyError: pass clsdict['Meta'] = meta return super().__new__(mcs, name, bases, clsdict)
def get_value(self, meta, base_classes_meta, mcs_args: McsArgs): value = super().get_value(meta, base_classes_meta, mcs_args) if value is not _missing: return value return controller_name( mcs_args.name, deep_getattr(mcs_args.clsdict, mcs_args.bases, REMOVE_SUFFIXES_ATTR))
def get_value(self, meta, base_classes_meta, mcs_args: McsArgs): value = super().get_value(meta, base_classes_meta, mcs_args) if value is not _missing: return value ctrl_name = controller_name(mcs_args.name, deep_getattr(mcs_args.clsdict, mcs_args.bases, REMOVE_SUFFIXES_ATTR)) return '/' + pluralize(ctrl_name.replace('_', '-'))
def __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) _set_up_class_dependency_injection(mcs_args) process_factory_meta_options( mcs_args, default_factory_class=_ServiceMetaOptionsFactory) # extended concrete services should not inherit their super's di name if deep_getattr({}, bases, '__di_name__', None): clsdict['__di_name__'] = None return super().__new__(*mcs_args)
def check_value(self, value, mcs_args: McsArgs): if not value: return if isinstance(value, (list, tuple)): assert all(callable(x) for x in value), \ f'The {self.name} meta option requires a list or tuple of callables' else: for method_name, decorators in value.items(): assert deep_getattr(mcs_args.clsdict, mcs_args.bases, method_name), \ f'The {method_name} was not found on {mcs_args.name}' assert all(callable(x) for x in decorators), \ f'Invalid decorator detected in the {self.name} meta option for ' \ f'the {method_name} key'
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'