#32186: Application's `ready()` method doesn't called when app's author missed 
to
define `default_app_config`
-----------------------------------------+------------------------
               Reporter:  Anthony        |          Owner:  nobody
                   Type:  Uncategorized  |         Status:  new
              Component:  Uncategorized  |        Version:  3.1
               Severity:  Normal         |       Keywords:
           Triage Stage:  Unreviewed     |      Has patch:  0
    Needs documentation:  0              |    Needs tests:  0
Patch needs improvement:  0              |  Easy pickings:  0
                  UI/UX:  0              |
-----------------------------------------+------------------------
 I think, the issue is applied to documentation specifically, but the code
 can do better too.

 If application is referenced in `INSTALLED_APPS` by package path rather
 than `AppConfig`s sublcass path, ''and'' application's author missed to
 define `default_app_config`, then application's initialization will be
 skipped silently. It leads to hard-to-debug bugs, especially with things
 that already hard-to-debug such as scheduling asynchronous jobs with
 signals.

 == Details

 In [https://docs.djangoproject.com/en/2.2/ref/applications/#for-
 application-authors "Applications"] documentation page, it is stated that
 application author need to provide subclass of `AppConfig`. Then, the user
 of application need to reference it in `INSTALLED_APPS` setting either by
 app's package path, or by `AppConfig` subclass.

 It is also stated that app's author ''can'' make the loading of his
 `AppConfig` subclass by pointing `default_app_config` variable in
 `__init__.py` to `AppConfig` subclass full dotted path:

  You can make your application load this AppConfig subclass by default as
 follows:

  {{{
   # rock_n_roll/__init__.py

   default_app_config = 'rock_n_roll.apps.RockNRollConfig'
  }}}

 Note that is not "required", nor "should" - you just "can". I treat it as
 "you can, if you will".

 
[https://docs.djangoproject.com/en/3.1/ref/applications/#django.apps.AppConfig.ready
 Later on], it is stated that

  `AppConfig.ready()`
  Subclasses can override this method to perform initialization tasks such
 as registering signals.

 And finally, in [https://docs.djangoproject.com/en/3.1/topics/signals
 /#connecting-receiver-functions "Signals"] documentation page, it is
 suggested to import application's signals in `.ready()` method.

 It is fleetingly stated, though, in
 [https://docs.djangoproject.com/en/3.1/ref/applications/#configuring-
 applications "Configuring applications"] that:

  If there is no `default_app_config`, Django uses the base `AppConfig`
 class

 Which means that application author's `AppConfig` subclass ''will not even
 evaluated'' - so, nor `.ready()` is called, too.

 The docs should explicitly **warn** (at least) an user that is is the case
 if app's author missed to define `default_app_config`, or user itself
 referenced application not by full `AppConfig` class.

 == The code

 It can do better, too.

 There is clear condition that custom `AppConfig` subclass is skipped,
 here:


 {{{
         else:
             try:
                 # If this works, the app module specifies an app config
 class.
                 entry = module.default_app_config
             except AttributeError:
                 # Otherwise, it simply uses the default app config class.
                 return cls(entry, module)
 }}}

 github
 https://github.com/django/django/blob/stable/3.1.x/django/apps/config.py#L110

 An user, again, should be explicitly warned (at least) that it is the
 case, for example with log event of `WARNING` level.

 Silently ignoring such a crucial nuance is worst possible way. Users can
 ([https://stackoverflow.com/search?q=django+signals+not+working and will,
 in my experience]) assume, for example, that subclassing `AppConfig` and
 overriding `.ready()` method is enough for registering their signals,
 which is far from truth. The solution could be to use full `AppConfig`
 paths, but seems like no one using it.

 In our current project, there is about 30 installed apps (w/o our own),
 and none of them referenced by `AppConfig`s subclasses:


 {{{
 INSTALLED_APPS = [
     'polymorphic',
     'watchman',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.messages',
     'collectfast',
     'django.contrib.staticfiles',
     'dal',
     'dal_select2',
     'dal_queryset_sequence',
     'django_admin_env_notice',
     'django.contrib.admin',
     'django.contrib.admindocs',
     'adminsortable2',
     'ckeditor',
     'ckeditor_uploader',
     'easy_pdf',
     'rest_framework',
     'django_filters',
     'djoser',
     'social_django',
     'rest_social_auth',
     'axes',
     'corsheaders',
     'drf_yasg',
     'django_extensions',
     'django.contrib.postgres',
     'psqlextra',
     'versatileimagefield',
 ]
 }}}

 The most popular reusable apps also suggest usage of just package path in
 their docs:

 https://www.django-rest-framework.org/#installation
 https://django-allauth.readthedocs.io/en/latest/installation.html#django
 https://github.com/django-extensions/django-extensions#installing-it
 https://github.com/adamchainz/django-cors-headers#setup

-- 
Ticket URL: <https://code.djangoproject.com/ticket/32186>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.cd2cfa91b0c3dfd68cbdae69770fe8f5%40djangoproject.com.

Reply via email to