def __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) if mcs_args.is_abstract: return super().__new__(*mcs_args) cls = super().__new__(*mcs_args) 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, mcs_args.getattr(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 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, mcs_args.getattr(REMOVE_SUFFIXES_ATTR))
def __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) _set_up_class_dependency_injection(mcs_args) if mcs_args.is_abstract: return super().__new__(*mcs_args) meta = mcs_args.getattr('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 Meta`` model attribute') model = None try: 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 meta_dict = dict(meta.__dict__) meta_dict.pop('model', None) clsdict['Meta'] = type('Meta', (_ModelSerializerMeta,), meta_dict) clsdict['Meta'].model = model return super().__new__(*mcs_args)
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, mcs_args.getattr(REMOVE_SUFFIXES_ATTR)) return '/' + pluralize(ctrl_name.replace('_', '-'))
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 mcs_args.getattr(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 __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) _set_up_class_dependency_injection(mcs_args) if mcs_args.is_abstract: return super().__new__(*mcs_args) meta = mcs_args.getattr('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 Meta`` model attribute') model = meta.model try: model = unchained.sqlalchemy_bundle.models[meta.model.__name__] except AttributeError as e: # this happens when attempting to generate documentation and the # sqlalchemy bundle hasn't been loaded safe_error = "'DeferredBundleFunctions' object has no attribute 'models'" if safe_error not in str(e): raise e except KeyError: pass meta_dict = dict(meta.__dict__) additional_fields = meta_dict.pop('additional', None) if additional_fields: fields = [ name for name, field in clsdict.items() if isinstance(field, Field) ] meta_dict['fields'] = fields + list(additional_fields) meta_dict.pop('model', None) clsdict['Meta'] = type('Meta', (_ModelSerializerMeta, ), meta_dict) clsdict['Meta'].model = model return super().__new__(*mcs_args)
def _set_up_class_dependency_injection(mcs_args: McsArgs): mcs_args.clsdict[_DI_AUTOMATICALLY_HANDLED] = True cls_attrs_to_inject = [ k for k, v in mcs_args.clsdict.items() if v == injectable ] try: mcs_args.clsdict[_INJECT_CLS_ATTRS] = \ cls_attrs_to_inject + mcs_args.getattr(_INJECT_CLS_ATTRS, []) except TypeError as e: if 'can only concatenate list (not "OptionalMetaclass") to list' not in str( e): raise e mcs_args.clsdict[_INJECT_CLS_ATTRS] = cls_attrs_to_inject if '__init__' not in mcs_args.clsdict and cls_attrs_to_inject: init = _inject_cls_attrs( _call_super_for_cls=f'{mcs_args.module}:{mcs_args.name}') init.__di_name__ = mcs_args.name init.__signature__ = inspect.signature(object) mcs_args.clsdict['__init__'] = init mcs_args.clsdict['__signature__'] = init.__signature__ elif '__init__' in mcs_args.clsdict: from .unchained import unchained init = unchained.inject()(mcs_args.clsdict['__init__']) init.__di_name__ = mcs_args.name mcs_args.clsdict['__init__'] = (init if not cls_attrs_to_inject else _inject_cls_attrs(_wrapped_fn=init)) mcs_args.clsdict['__signature__'] = init.__signature__ for attr, value in mcs_args.clsdict.items(): if isinstance(value, FunctionType): if not attr.startswith('__') and not hasattr( value, '__signature__'): from .unchained import unchained mcs_args.clsdict[attr] = unchained.inject()(value) value.__di_name__ = (mcs_args.name if value.__name__ == '__init__' else f'{mcs_args.name}.{value.__name__}')