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()
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()
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
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)
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
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 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)
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()
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)
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, })
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)
import inspect
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, )
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)
import sys
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()