#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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.cd2cfa91b0c3dfd68cbdae69770fe8f5%40djangoproject.com.

Reply via email to