Esempio n. 1
0
    def _validate_and_setup_integrations(self) -> None:
        """
        Validate the INTEGRATIONS settings and verify each integration
        """
        for integration in self.INTEGRATIONS:

            # Make sure all integration methods are callable
            for method, name in [
                (integration.setup, 'setup'),
                (integration.run, 'run'),
                (integration.cleanup, 'cleanup'),
            ]:
                # Make sure the methods are callable
                if not callable(method):
                    raise ImproperlyConfigured(
                        f'Integration method `{name}` needs to be made callable for `{integration.identifier}`.'
                    )

                # Make sure the method takes kwargs
                if name in ['run', 'cleanup'] and not func_accepts_kwargs(method):
                    raise ImproperlyConfigured(
                        f'Integration method `{name}` must '
                        f'accept keyword arguments (**kwargs) for `{integration.identifier}`.'
                    )

            # Run validate method
            integration.setup()
Esempio n. 2
0
    def form_class(self):
        fields = OrderedDict(
            (("required_css_class", "required"), ("error_css_class", "error"))
        )

        for field in self.fields.all():
            field.add_formfield(fields, self)

        validators = []
        cfg = dict(self.CONFIG_OPTIONS)
        for key, config in self.config.items():
            try:
                validator = cfg[key]["validate"]
            except KeyError:
                pass
            else:
                if func_accepts_kwargs(validator):
                    validator = partial(validator, config=config, model_instance=self)
                else:
                    warnings.warn(
                        "validate of %r should accept **kwargs" % (key,),
                        DeprecationWarning,
                    )
                validators.append(validator)

        class Form(forms.Form):
            def clean(self):
                data = super(Form, self).clean()
                for validator in validators:
                    validator(self, data)
                return data

        return type(str("Form%s" % self.pk), (Form,), fields)
    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
        """
        参数说明:

        receiver     : 信号接收者,通常是一个可调用对象
        sender       : 信号发送者,可能是某个映射类实例
        weak         : TODO 布尔值,默认是 True 
        dispatch_uid : None
        """
        from django.conf import settings

        # If DEBUG is on, check that we got a good receiver
        if settings.configured and settings.DEBUG:
            assert callable(receiver), "Signal receivers must be callable."

            # Check for **kwargs
            if not func_accepts_kwargs(receiver):
                raise ValueError(
                    "Signal receivers must accept keyword arguments (**kwargs)."
                )

        if dispatch_uid:
            lookup_key = (dispatch_uid, _make_id(sender))
        else:
            # 下面的 _make_id 方法定义在当前模块中,返回值是参数的内存地址
            lookup_key = (_make_id(receiver), _make_id(sender))

        if weak:
            # 这个 weafref 是 Python 内置模块,其作用是创建弱引用对象
            ref = weakref.ref
            # 把普通对象赋值给一个新的变量
            receiver_object = receiver
            # 通常 receiver 就是一函数,它没有这俩属性
            if hasattr(receiver, '__self__') and hasattr(receiver, '__func__'):
                ref = weakref.WeakMethod
                receiver_object = receiver.__self__
            # 创建一个弱引用对象赋值给原变量
            receiver = ref(receiver)
            # 这里 weakref.finalize 是一个类对象,该类的实例叫做「垃圾回收终结器」
            # 这步操作使得第一个参数被当做垃圾回收时,顺便调用第二个参数
            # 据说这种用法比设置回调函数好在垃圾被回收前「垃圾回收终结器」一直存在
            weakref.finalize(receiver_object, self._remove_receiver)

        with self.lock:
            self._clear_dead_receivers()
            if not any(r_key == lookup_key for r_key, _ in self.receivers):
                # self 初始化时,self.receivers 是一个空列表
                # lookup_key 是一个元组,里面是参数 receiver 和 sender 的内存地址
                # 此时的 receiver 通常是一个函数的弱引用对象
                self.receivers.append((lookup_key, receiver))
                # 此时的 self.receive 是这样的:
                # [
                #  (
                #   (信号接收者的内存地址, 信号发出者的内存地址),
                #   信号接收函数
                #  ),
                # ]
            self.sender_receivers_cache.clear()
Esempio n. 4
0
 def inner(check):
     if not func_accepts_kwargs(check):
         raise TypeError(
             'Check functions must accept keyword arguments (**kwargs).'
         )
     check.tags = tags
     checks = self.deployment_checks if kwargs.get(
         'deploy') else self.registered_checks
     checks.add(check)
     return check
Esempio n. 5
0
    def as_widget(self,
                  widget=None,
                  attrs=None,
                  only_initial=False,
                  using_template=None,
                  template_name=None):
        if using_template is None:
            using_template = self.field.using_template or False

        if template_name is None:
            template_name = self.field.template_name

        # 一下代码段为Django的源码
        if not widget:
            widget = self.field.widget

        if self.field.localize:
            widget.is_localized = True

        attrs = attrs or {}
        attrs = self.build_widget_attrs(attrs, widget)
        auto_id = self.auto_id
        if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
            if not only_initial:
                attrs['id'] = auto_id
            else:
                attrs['id'] = self.html_initial_id

        if not only_initial:
            name = self.html_name
        else:
            name = self.html_initial_name

        kwargs = {}
        if func_supports_parameter(widget.render,
                                   'renderer') or func_accepts_kwargs(
                                       widget.render):
            kwargs['renderer'] = self.form.renderer
        else:
            warnings.warn(
                'Add the `renderer` argument to the render() method of %s. '
                'It will be mandatory in Django 2.1.' % widget.__class__,
                RemovedInDjango21Warning,
                stacklevel=2,
            )
        return widget.render(name=name,
                             value=self.value(),
                             attrs=attrs,
                             context=self.get_render_context(),
                             using_template=using_template,
                             template_name=template_name,
                             **kwargs)
Esempio n. 6
0
    def clean(self):
        """Clean the form and the sub-form for the selected search backend.

        Returns:
            dict:
            The cleaned data.
        """
        cleaned_data = self.cleaned_data

        if cleaned_data['search_enable']:
            search_backend_id = cleaned_data.get('search_backend_id')

            # The search_backend_id field is only available if the backend
            # passed validation.
            if search_backend_id:
                backend_form = self.search_backend_forms[search_backend_id]

                # Validate the configuration form.
                if backend_form.is_valid():
                    # Validate the search backend, ensuring the configuration
                    # is correct.
                    search_backend = \
                        search_backend_registry.get_search_backend(
                            search_backend_id)
                    configuration = \
                        search_backend.get_configuration_from_form_data(
                            backend_form.cleaned_data)

                    try:
                        if func_accepts_kwargs(search_backend.validate):
                            search_backend.validate(
                                configuration=configuration)
                        else:
                            RemovedInReviewBoard50Warning.warn(
                                '%s.validate() must accept keyword '
                                'arguments. This will be required in '
                                'Review Board 5.0.'
                                % search_backend.__class__.__name__)
                            search_backend.validate()
                    except ValidationError as e:
                        self.add_error('search_backend_id', e.error_list)
                else:
                    # The configuration form had issues.
                    self._errors.update(backend_form.errors)

        return cleaned_data
Esempio n. 7
0
    def as_widget(self, widget=None, attrs=None, only_initial=False):
        """
        Renders the field by rendering the passed widget, adding any HTML
        attributes passed as attrs.  If no widget is specified, then the
        field's default widget will be used.
        """
        if not widget:
            widget = self.field.widget

        if self.field.localize:
            widget.is_localized = True

        attrs = attrs or {}
        attrs = self.build_widget_attrs(attrs, widget)
        auto_id = self.auto_id
        if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
            if not only_initial:
                attrs['id'] = auto_id
            else:
                attrs['id'] = self.html_initial_id

        if not only_initial:
            name = self.html_name
        else:
            name = self.html_initial_name

        kwargs = {}
        if func_supports_parameter(widget.render,
                                   'renderer') or func_accepts_kwargs(
                                       widget.render):
            kwargs['renderer'] = self.form.renderer
        else:
            warnings.warn(
                'Add the `renderer` argument to the render() method of %s. '
                'It will be mandatory in Django 2.1.' % widget.__class__,
                RemovedInDjango21Warning,
                stacklevel=2,
            )
        html = widget.render(name=name,
                             value=self.value(),
                             attrs=attrs,
                             **kwargs)
        return force_text(html)
Esempio n. 8
0
    def as_widget(self, widget=None, attrs=None, only_initial=False):
        """
        Renders the field by rendering the passed widget, adding any HTML
        attributes passed as attrs.  If no widget is specified, then the
        field's default widget will be used.
        """
        if not widget:
            widget = self.field.widget

        if self.field.localize:
            widget.is_localized = True

        attrs = attrs or {}
        attrs = self.build_widget_attrs(attrs, widget)
        auto_id = self.auto_id
        if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
            if not only_initial:
                attrs['id'] = auto_id
            else:
                attrs['id'] = self.html_initial_id

        if not only_initial:
            name = self.html_name
        else:
            name = self.html_initial_name

        kwargs = {}
        if func_supports_parameter(widget.render, 'renderer') or func_accepts_kwargs(widget.render):
            kwargs['renderer'] = self.form.renderer
        else:
            warnings.warn(
                'Add the `renderer` argument to the render() method of %s. '
                'It will be mandatory in Django 2.1.' % widget.__class__,
                RemovedInDjango21Warning, stacklevel=2,
            )
        html = widget.render(
            name=name,
            value=self.value(),
            attrs=attrs,
            **kwargs
        )
        return force_text(html)
    def __init__(self, func):

        # Store the reference to the registered function
        self.function = func

        # @rpc_method decorator parameters
        self._external_name = getattr(func, 'modernrpc_name', func.__name__)
        self.entry_point = getattr(func, 'modernrpc_entry_point')
        self.protocol = getattr(func, 'modernrpc_protocol')
        self.str_standardization = getattr(func, 'str_standardization')
        self.str_std_encoding = getattr(func, 'str_standardization_encoding')
        # Authentication related attributes
        self.predicates = getattr(func, 'modernrpc_auth_predicates', None)
        self.predicates_params = getattr(func,
                                         'modernrpc_auth_predicates_params',
                                         ())

        # List method's positional arguments
        # We can't use django.utils.inspect.get_func_args() with Python 2, because this function remove the first
        # argument in returned list. This is supposed to remove the first 'self' argument, but doesn't fork well
        # for global functions.
        # For Python 2, we will prefer django.utils.inspect.getargspec(func)[0]. This will work as expected, even if
        # the function has been removed in Django 2.0, since Django 2 doesn't work with Python 2
        self.args = inspect.get_func_args(
            func) if six.PY3 else inspect.getargspec(func)[0]
        # Does the method accept additional kwargs dict?
        self.accept_kwargs = inspect.func_accepts_kwargs(func)

        # Contains the signature of the method, as returned by "system.methodSignature"
        self.signature = []
        # Contains the method's docstring, in HTML form
        self.html_doc = ''
        # Contains doc about arguments and their type. We store this in an ordered dict, so the args documentation
        # keep the order defined in docstring
        self.args_doc = collections.OrderedDict()
        # Contains doc about return type and return value
        self.return_doc = {}

        # Docstring parsing
        self.raw_docstring = self.parse_docstring(func.__doc__)
        self.html_doc = self.raw_docstring_to_html(self.raw_docstring)
Esempio n. 10
0
    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
        """
        Connect receiver to sender for signal.

        Arguments:

            receiver
                A function or an instance method which is to receive signals.
                Receivers must be hashable objects.

                If weak is True, then receiver must be weak referenceable.

                Receivers must be able to accept keyword arguments.

                If a receiver is connected with a dispatch_uid argument, it
                will not be added if another receiver was already connected
                with that dispatch_uid.

            sender
                The sender to which the receiver should respond. Must either be
                of type Signal, or None to receive events from any sender.

            weak
                Whether to use weak references to the receiver. By default, the
                module will attempt to use weak references to the receiver
                objects. If this parameter is false, then strong references will
                be used.

            dispatch_uid
                An identifier used to uniquely identify a particular instance of
                a receiver. This will usually be a string, though it may be
                anything hashable.
        """
        from django.conf import settings

        # If DEBUG is on, check that we got a good receiver
        if settings.configured and settings.DEBUG:
            assert callable(receiver), "Signal receivers must be callable."

            # Check for **kwargs
            if not func_accepts_kwargs(receiver):
                raise ValueError("Signal receivers must accept keyword arguments (**kwargs).")

        if dispatch_uid:
            lookup_key = (dispatch_uid, _make_id(sender))
        else:
            lookup_key = (_make_id(receiver), _make_id(sender))

        if weak:
            ref = weakref.ref
            receiver_object = receiver
            # Check for bound methods
            if hasattr(receiver, '__self__') and hasattr(receiver, '__func__'):
                ref = WeakMethod
                receiver_object = receiver.__self__
            if six.PY3:
                receiver = ref(receiver)
                weakref.finalize(receiver_object, self._remove_receiver)
            else:
                receiver = ref(receiver, self._remove_receiver)

        with self.lock:
            self._clear_dead_receivers()
            for r_key, _ in self.receivers:
                if r_key == lookup_key:
                    break
            else:
                self.receivers.append((lookup_key, receiver))
            self.sender_receivers_cache.clear()
Esempio n. 11
0
    def get_context_data(self, **kwargs):
        model_name = self.kwargs['model_name']
        # Get the model class.
        try:
            app_config = apps.get_app_config(self.kwargs['app_label'])
        except LookupError:
            raise Http404(_("App %(app_label)r not found") % self.kwargs)
        try:
            model = app_config.get_model(model_name)
        except LookupError:
            raise Http404(_("Model %(model_name)r not found in app %(app_label)r") % self.kwargs)

        opts = model._meta

        title, body, metadata = utils.parse_docstring(model.__doc__)
        if title:
            title = utils.parse_rst(title, 'model', _('model:') + model_name)
        if body:
            body = utils.parse_rst(body, 'model', _('model:') + model_name)

        # Gather fields/field descriptions.
        fields = []
        for field in opts.fields:
            # ForeignKey is a special case since the field will actually be a
            # descriptor that returns the other object
            if isinstance(field, models.ForeignKey):
                data_type = field.remote_field.model.__name__
                app_label = field.remote_field.model._meta.app_label
                verbose = utils.parse_rst(
                    (_("the related `%(app_label)s.%(data_type)s` object") % {
                        'app_label': app_label, 'data_type': data_type,
                    }),
                    'model',
                    _('model:') + data_type,
                )
            else:
                data_type = get_readable_field_data_type(field)
                verbose = field.verbose_name
            fields.append({
                'name': field.name,
                'data_type': data_type,
                'verbose': verbose or '',
                'help_text': field.help_text,
            })

        # Gather many-to-many fields.
        for field in opts.many_to_many:
            data_type = field.remote_field.model.__name__
            app_label = field.remote_field.model._meta.app_label
            verbose = _("related `%(app_label)s.%(object_name)s` objects") % {
                'app_label': app_label,
                'object_name': data_type,
            }
            fields.append({
                'name': "%s.all" % field.name,
                "data_type": 'List',
                'verbose': utils.parse_rst(_("all %s") % verbose, 'model', _('model:') + opts.model_name),
            })
            fields.append({
                'name': "%s.count" % field.name,
                'data_type': 'Integer',
                'verbose': utils.parse_rst(_("number of %s") % verbose, 'model', _('model:') + opts.model_name),
            })

        methods = []
        # Gather model methods.
        for func_name, func in model.__dict__.items():
            if inspect.isfunction(func):
                try:
                    for exclude in MODEL_METHODS_EXCLUDE:
                        if func_name.startswith(exclude):
                            raise StopIteration
                except StopIteration:
                    continue
                verbose = func.__doc__
                if verbose:
                    verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.model_name)
                # If a method has no arguments, show it as a 'field', otherwise
                # as a 'method with arguments'.
                if func_has_no_args(func) and not func_accepts_kwargs(func) and not func_accepts_var_args(func):
                    fields.append({
                        'name': func_name,
                        'data_type': get_return_data_type(func_name),
                        'verbose': verbose or '',
                    })
                else:
                    arguments = get_func_full_args(func)
                    # Join arguments with ', ' and in case of default value,
                    # join it with '='. Use repr() so that strings will be
                    # correctly displayed.
                    print_arguments = ', '.join([
                        '='.join(list(arg_el[:1]) + [repr(el) for el in arg_el[1:]])
                        for arg_el in arguments
                    ])
                    methods.append({
                        'name': func_name,
                        'arguments': print_arguments,
                        'verbose': verbose or '',
                    })

        # Gather related objects
        for rel in opts.related_objects:
            verbose = _("related `%(app_label)s.%(object_name)s` objects") % {
                'app_label': rel.related_model._meta.app_label,
                'object_name': rel.related_model._meta.object_name,
            }
            accessor = rel.get_accessor_name()
            fields.append({
                'name': "%s.all" % accessor,
                'data_type': 'List',
                'verbose': utils.parse_rst(_("all %s") % verbose, 'model', _('model:') + opts.model_name),
            })
            fields.append({
                'name': "%s.count" % accessor,
                'data_type': 'Integer',
                'verbose': utils.parse_rst(_("number of %s") % verbose, 'model', _('model:') + opts.model_name),
            })
        kwargs.update({
            'name': '%s.%s' % (opts.app_label, opts.object_name),
            'summary': title,
            'description': body,
            'fields': fields,
            'methods': methods,
        })
        return super().get_context_data(**kwargs)
Esempio n. 12
0
    def get_context_data(self, **kwargs):
        model_name = self.kwargs["model_name"]
        # Get the model class.
        try:
            app_config = apps.get_app_config(self.kwargs["app_label"])
        except LookupError:
            raise Http404(_("App %(app_label)r not found") % self.kwargs)
        try:
            model = app_config.get_model(model_name)
        except LookupError:
            raise Http404(
                _("Model %(model_name)r not found in app %(app_label)r") %
                self.kwargs)

        opts = model._meta

        title, body, metadata = utils.parse_docstring(model.__doc__)
        title = title and utils.parse_rst(title, "model",
                                          _("model:") + model_name)
        body = body and utils.parse_rst(body, "model",
                                        _("model:") + model_name)

        # Gather fields/field descriptions.
        fields = []
        for field in opts.fields:
            # ForeignKey is a special case since the field will actually be a
            # descriptor that returns the other object
            if isinstance(field, models.ForeignKey):
                data_type = field.remote_field.model.__name__
                app_label = field.remote_field.model._meta.app_label
                verbose = utils.parse_rst(
                    (_("the related `%(app_label)s.%(data_type)s` object") % {
                        "app_label": app_label,
                        "data_type": data_type,
                    }),
                    "model",
                    _("model:") + data_type,
                )
            else:
                data_type = get_readable_field_data_type(field)
                verbose = field.verbose_name
            fields.append({
                "name": field.name,
                "data_type": data_type,
                "verbose": verbose or "",
                "help_text": field.help_text,
            })

        # Gather many-to-many fields.
        for field in opts.many_to_many:
            data_type = field.remote_field.model.__name__
            app_label = field.remote_field.model._meta.app_label
            verbose = _("related `%(app_label)s.%(object_name)s` objects") % {
                "app_label": app_label,
                "object_name": data_type,
            }
            fields.append({
                "name":
                "%s.all" % field.name,
                "data_type":
                "List",
                "verbose":
                utils.parse_rst(
                    _("all %s") % verbose, "model",
                    _("model:") + opts.model_name),
            })
            fields.append({
                "name":
                "%s.count" % field.name,
                "data_type":
                "Integer",
                "verbose":
                utils.parse_rst(
                    _("number of %s") % verbose,
                    "model",
                    _("model:") + opts.model_name,
                ),
            })

        methods = []
        # Gather model methods.
        for func_name, func in model.__dict__.items():
            if inspect.isfunction(func) or isinstance(
                    func, (cached_property, property)):
                try:
                    for exclude in MODEL_METHODS_EXCLUDE:
                        if func_name.startswith(exclude):
                            raise StopIteration
                except StopIteration:
                    continue
                verbose = func.__doc__
                verbose = verbose and (utils.parse_rst(
                    cleandoc(verbose), "model",
                    _("model:") + opts.model_name))
                # Show properties, cached_properties, and methods without
                # arguments as fields. Otherwise, show as a 'method with
                # arguments'.
                if isinstance(func, (cached_property, property)):
                    fields.append({
                        "name": func_name,
                        "data_type": get_return_data_type(func_name),
                        "verbose": verbose or "",
                    })
                elif (method_has_no_args(func)
                      and not func_accepts_kwargs(func)
                      and not func_accepts_var_args(func)):
                    fields.append({
                        "name": func_name,
                        "data_type": get_return_data_type(func_name),
                        "verbose": verbose or "",
                    })
                else:
                    arguments = get_func_full_args(func)
                    # Join arguments with ', ' and in case of default value,
                    # join it with '='. Use repr() so that strings will be
                    # correctly displayed.
                    print_arguments = ", ".join([
                        "=".join([arg_el[0], *map(repr, arg_el[1:])])
                        for arg_el in arguments
                    ])
                    methods.append({
                        "name": func_name,
                        "arguments": print_arguments,
                        "verbose": verbose or "",
                    })

        # Gather related objects
        for rel in opts.related_objects:
            verbose = _("related `%(app_label)s.%(object_name)s` objects") % {
                "app_label": rel.related_model._meta.app_label,
                "object_name": rel.related_model._meta.object_name,
            }
            accessor = rel.get_accessor_name()
            fields.append({
                "name":
                "%s.all" % accessor,
                "data_type":
                "List",
                "verbose":
                utils.parse_rst(
                    _("all %s") % verbose, "model",
                    _("model:") + opts.model_name),
            })
            fields.append({
                "name":
                "%s.count" % accessor,
                "data_type":
                "Integer",
                "verbose":
                utils.parse_rst(
                    _("number of %s") % verbose,
                    "model",
                    _("model:") + opts.model_name,
                ),
            })
        return super().get_context_data(
            **{
                **kwargs,
                "name": opts.label,
                "summary": title,
                "description": body,
                "fields": fields,
                "methods": methods,
            })
Esempio n. 13
0
 def test_func_accepts_kwargs(self):
     self.assertIs(inspect.func_accepts_kwargs(Person.just_args), False)
     self.assertIs(inspect.func_accepts_kwargs(Person.all_kinds), True)
Esempio n. 14
0
import inspect
Esempio n. 15
0
    def __init__(self) -> None:
        self.GUID_HEADER_NAME = 'Correlation-ID'
        self.VALIDATE_GUID = True
        self.RETURN_HEADER = True
        self.EXPOSE_HEADER = True
        self.INTEGRATIONS = []
        self.SKIP_CLEANUP = None  # Deprecated - to be removed in the next major version

        if hasattr(django_settings, 'DJANGO_GUID'):
            _settings = django_settings.DJANGO_GUID

            # Set user settings if provided
            for setting, value in _settings.items():
                if hasattr(self, setting):
                    setattr(self, setting, value)
                else:
                    raise ImproperlyConfigured(
                        f'{setting} is not a valid setting for django_guid')

            if not isinstance(self.VALIDATE_GUID, bool):
                raise ImproperlyConfigured('VALIDATE_GUID must be a boolean')
            if not isinstance(self.GUID_HEADER_NAME, str):
                raise ImproperlyConfigured('GUID_HEADER_NAME must be a string'
                                           )  # Note: Case insensitive
            if not isinstance(self.RETURN_HEADER, bool):
                raise ImproperlyConfigured('RETURN_HEADER must be a boolean')
            if not isinstance(self.EXPOSE_HEADER, bool):
                raise ImproperlyConfigured('EXPOSE_HEADER must be a boolean')
            if not isinstance(self.INTEGRATIONS, list):
                raise ImproperlyConfigured('INTEGRATIONS must be an array')

            for integration in self.INTEGRATIONS:

                # Make sure all integration methods are callable
                for method, name in [
                    (integration.setup, 'setup'),
                    (integration.run, 'run'),
                    (integration.cleanup, 'cleanup'),
                ]:
                    # Make sure the methods are callable
                    if not callable(method):
                        raise ImproperlyConfigured(
                            f'Integration method `{name}` needs to be made callable for `{integration.identifier}`.'
                        )

                    # Make sure the method takes kwargs
                    if name in ['run', 'cleanup'
                                ] and not func_accepts_kwargs(method):
                        raise ImproperlyConfigured(
                            f'Integration method `{name}` must '
                            f'accept keyword arguments (**kwargs) for `{integration.identifier}`.'
                        )

                # Run validate method
                integration.setup()

            if 'SKIP_CLEANUP' in _settings:
                warn(
                    'SKIP_CLEANUP was deprecated in v1.2.0, and no longer impacts package behaviour. '
                    'Please remove it from your DJANGO_GUID settings.',
                    DeprecationWarning,
                )
Esempio n. 16
0
    def get_context_data(self, **kwargs):
        model_name = self.kwargs['model_name']
        # Get the model class.
        try:
            app_config = apps.get_app_config(self.kwargs['app_label'])
        except LookupError:
            raise Http404(_("App %(app_label)r not found") % self.kwargs)
        try:
            model = app_config.get_model(model_name)
        except LookupError:
            raise Http404(
                _("Model %(model_name)r not found in app %(app_label)r") %
                self.kwargs)

        opts = model._meta

        title, body, metadata = utils.parse_docstring(model.__doc__)
        if title:
            title = utils.parse_rst(title, 'model', _('model:') + model_name)
        if body:
            body = utils.parse_rst(body, 'model', _('model:') + model_name)

        # Gather fields/field descriptions.
        fields = []
        for field in opts.fields:
            # ForeignKey is a special case since the field will actually be a
            # descriptor that returns the other object
            if isinstance(field, models.ForeignKey):
                data_type = field.remote_field.model.__name__
                app_label = field.remote_field.model._meta.app_label
                verbose = utils.parse_rst(
                    (_("the related `%(app_label)s.%(data_type)s` object") % {
                        'app_label': app_label,
                        'data_type': data_type,
                    }),
                    'model',
                    _('model:') + data_type,
                )
            else:
                data_type = get_readable_field_data_type(field)
                verbose = field.verbose_name
            fields.append({
                'name': field.name,
                'data_type': data_type,
                'verbose': verbose or '',
                'help_text': field.help_text,
            })

        # Gather many-to-many fields.
        for field in opts.many_to_many:
            data_type = field.remote_field.model.__name__
            app_label = field.remote_field.model._meta.app_label
            verbose = _("related `%(app_label)s.%(object_name)s` objects") % {
                'app_label': app_label,
                'object_name': data_type,
            }
            fields.append({
                'name':
                "%s.all" % field.name,
                "data_type":
                'List',
                'verbose':
                utils.parse_rst(
                    _("all %s") % verbose, 'model',
                    _('model:') + opts.model_name),
            })
            fields.append({
                'name':
                "%s.count" % field.name,
                'data_type':
                'Integer',
                'verbose':
                utils.parse_rst(
                    _("number of %s") % verbose, 'model',
                    _('model:') + opts.model_name),
            })

        methods = []
        # Gather model methods.
        for func_name, func in model.__dict__.items():
            if inspect.isfunction(func):
                try:
                    for exclude in MODEL_METHODS_EXCLUDE:
                        if func_name.startswith(exclude):
                            raise StopIteration
                except StopIteration:
                    continue
                verbose = func.__doc__
                if verbose:
                    verbose = utils.parse_rst(utils.trim_docstring(verbose),
                                              'model',
                                              _('model:') + opts.model_name)
                # If a method has no arguments, show it as a 'field', otherwise
                # as a 'method with arguments'.
                if func_has_no_args(func) and not func_accepts_kwargs(
                        func) and not func_accepts_var_args(func):
                    fields.append({
                        'name': func_name,
                        'data_type': get_return_data_type(func_name),
                        'verbose': verbose or '',
                    })
                else:
                    arguments = get_func_full_args(func)
                    # Join arguments with ', ' and in case of default value,
                    # join it with '='. Use repr() so that strings will be
                    # correctly displayed.
                    print_arguments = ', '.join([
                        '='.join(
                            list(arg_el[:1]) + [repr(el) for el in arg_el[1:]])
                        for arg_el in arguments
                    ])
                    methods.append({
                        'name': func_name,
                        'arguments': print_arguments,
                        'verbose': verbose or '',
                    })

        # Gather related objects
        for rel in opts.related_objects:
            verbose = _("related `%(app_label)s.%(object_name)s` objects") % {
                'app_label': rel.related_model._meta.app_label,
                'object_name': rel.related_model._meta.object_name,
            }
            accessor = rel.get_accessor_name()
            fields.append({
                'name':
                "%s.all" % accessor,
                'data_type':
                'List',
                'verbose':
                utils.parse_rst(
                    _("all %s") % verbose, 'model',
                    _('model:') + opts.model_name),
            })
            fields.append({
                'name':
                "%s.count" % accessor,
                'data_type':
                'Integer',
                'verbose':
                utils.parse_rst(
                    _("number of %s") % verbose, 'model',
                    _('model:') + opts.model_name),
            })
        kwargs.update({
            'name': '%s.%s' % (opts.app_label, opts.object_name),
            'summary': title,
            'description': body,
            'fields': fields,
            'methods': methods,
        })
        return super(ModelDetailView, self).get_context_data(**kwargs)
Esempio n. 17
0
import sys
Esempio n. 18
0
    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
        """
        Connect receiver to sender for signal.

        Arguments:

            receiver
                A function or an instance method which is to receive signals.
                Receivers must be hashable objects.

                If weak is True, then receiver must be weak referenceable.

                Receivers must be able to accept keyword arguments.

                If a receiver is connected with a dispatch_uid argument, it
                will not be added if another receiver was already connected
                with that dispatch_uid.

            sender
                The sender to which the receiver should respond. Must either be
                a Python object, or None to receive events from any sender.

            weak
                Whether to use weak references to the receiver. By default, the
                module will attempt to use weak references to the receiver
                objects. If this parameter is false, then strong references will
                be used.

            dispatch_uid
                An identifier used to uniquely identify a particular instance of
                a receiver. This will usually be a string, though it may be
                anything hashable.
        """
        # 加载django 配置
        from django.conf import settings

        # If DEBUG is on, check that we got a good receiver
        # 检查接收者的合法性,必须是可被调用的。
        if settings.configured and settings.DEBUG:
            #  断言接收者必须是一个可调用对象
            assert callable(receiver), "Signal receivers must be callable."

            # Check for **kwargs
            # 接收者必须**kwargs定义来接受参数,要求我们定义星号处理方法必须是**kwargs
            if not func_accepts_kwargs(receiver):
                raise ValueError(
                    "Signal receivers must accept keyword arguments (**kwargs)."
                )

        # dispatch_uid 接收者身份ID,唯一的,通常是一个str类型
        if dispatch_uid:
            lookup_key = (dispatch_uid, _make_id(sender))
        else:
            # 注意查询key使用了receiver+sender的组合id作为key值
            lookup_key = (_make_id(receiver), _make_id(sender))

        # weak默认值True,是否使用弱引用[另一个主题],主要解决缓存对象回收问题
        if weak:
            ref = weakref.ref
            receiver_object = receiver
            # Check for bound methods,检查是对象方法
            if hasattr(receiver, '__self__') and hasattr(receiver, '__func__'):
                ref = weakref.WeakMethod
                receiver_object = receiver.__self__

            # 创建若引用receiver
            receiver = ref(receiver)
            # 注册一个回调处理方法,当receiver_object被垃圾回收期回收的时候,调用
            # _remove_receiver 标识下有receiver已经死亡,可以移除了。 主要是在多线程场景下面可能发生
            weakref.finalize(receiver_object, self._remove_receiver)

        # 加锁,添加receiver,到我们的列表中
        with self.lock:
            # 清理已经死掉的receiver
            self._clear_dead_receivers()
            # 如果不存在则添加到列表
            if not any(r_key == lookup_key for r_key, _ in self.receivers):
                self.receivers.append((lookup_key, receiver))
            # 清理缓存,因为我们新增内容了
            self.sender_receivers_cache.clear()