radon icon indicating copy to clipboard operation
radon copied to clipboard

Calculating the complexity of decorator functions with nested functions

Open tuze-kuyucu opened this issue 6 years ago • 2 comments

Radon returns cc value of A for decorators with inner functions, I guess this is a known issue. Is there any planned support for this?

tuze-kuyucu avatar Oct 31 '18 13:10 tuze-kuyucu

I apologize for the long delay. Could you elaborate on the issue? It's possible that a decorator contains inner functions and still have a total CC such that the rank is A.

rubik avatar Jan 26 '19 13:01 rubik

Hi! Here is the function in question, which radon ranks with an A:

def event(use_annotations=False) -> Callable[[F], F]:
    def decorator(f: F) -> F:
        sig = signature(f)
        if use_annotations:
            params: Dict[str, fields.Field] = OrderedDict()
            for name, param in sig.parameters.items():
                if name == "self":
                    continue
                annotation = param.annotation
                default = param.default
                if annotation == Parameter.empty:
                    allow_none = default is None
                    if default == Parameter.empty:
                        params[name] = fields.Field(required=True, allow_none=allow_none)
                    else:
                        params[name] = fields.Field(required=True, allow_none=allow_none, missing=default)
                else:
                    params[name] = make_field_from_type_annotation(annotation, default)
            class_name = "".join(x.capitalize() for x in f.__name__.split("_")) + "Schema"
            params["Meta"] = Meta
            schema_class = type(class_name, (Schema,), params)
            schema = schema_class()
        else:
            schema_class = None
            schema = None

        @functools.wraps(f)
        def wrapper(self, *args, **kwargs):
            return_value = f(self, *args, **kwargs)
            bound = sig.bind(self, *args, **kwargs)
            arguments = bound.arguments
            del arguments["self"]
            if schema:
                result = schema.dumps(arguments)
                if result.errors:
                    raise ValueError(str(result.errors))
                dumps = result.data
            else:
                dumps = mujson.dumps(arguments)
            self._uncommitted_events.append(
                Event(
                    type=f.__name__,
                    stream_kind=self.STREAM_KIND,
                    stream_id=self._id,
                    data=dumps.encode(),
                ))
            return return_value

        cast(Any, wrapper).schema_class = schema_class
        cast(Any, wrapper).schema = schema
        return cast(F, wrapper)

    return decorator

tuze-kuyucu avatar Jan 30 '19 08:01 tuze-kuyucu