Repository: translate/pootle

Issue:
Import warning when virtualfolder is not in INSTALLED_APPS
Since recently we started to get some warnings related to virtual folders, even if we explicitly make no use of them:

``` python
RemovedInDjango19Warning: Model class virtualfolder.models.VirtualFolder doesn't declare an explicit app_label and either isn't in an application in INSTALLED_APPS or else was imported before its application was loaded. This will no longer be supported in Django 1.9.
  class VirtualFolder(models.Model):

RemovedInDjango19Warning: Model class virtualfolder.models.VirtualFolderTreeItem doesn't declare an explicit app_label and either isn't in an application in INSTALLED_APPS or else was imported before its application was loaded. This will no longer be supported in Django 1.9.
  class VirtualFolderTreeItem(models.Model, CachedTreeItem):
```

If I'm not mistaken these are reported since `virtualfolder.models` is being imported regardless of `virtualfolder` being in `INSTALLED_APPS`, so Django complains about it in this case.

While adding the suggested `app_label` silences the warning, I'm not 100% sure this is the right way to proceed.



Discussion:
The right way to proceed is to add `app_label` and conditionally import `virtualfolder` app.

> If I'm not mistaken these are reported since virtualfolder.models is being imported regardless of virtualfolder being in INSTALLED_APPS, so Django complains about it in this case.

as @unho has said we need to fix the virtualfolder app to make it compatible

atm when you install Pootle, you install `virtualfolders` - the imports should be explicit and at the top of the modules, even if virtualfolders is not in installed_apps and they are not made use of.

@julen How did you trigger these warnings? Were you running Django 1.9?

Django 1.8, simply remove `virtualfolders` from `INSTALLED_APPS` in your settings and any view importing such modules will trigger it.

@julen @unho i understand better the problem now - we do need better separation of virtualfolders before we can support django 1.9

@julen I see these warnings in our production server logs now. Does it mean that `app_label` no longer silences these, or that we don't have it enabled in production?

@iafan i think its because you dont have virtualfolders in INSTALLED_APPS, so the `app_label` has no effect.

I have a couple of PRs that are gradually moving all of the virtualfolder code into a plugin. That will fix this problem properly

Yeah @iafan, I realized these are now showing up (and often) in the logs, adding up a lot of noise and potentially masking other errors unfortunately.

I checked this again and adding an `app_label` to virtual folders doesn't make any difference at all (it wasn't there), so the problem is that a `models` module from an app which is not installed is being imported — the same happened with the commenting code as reported in #4657.

Since we definitely want to avoid our logs being filled up with these warnings as soon as possible, I believe the interim solution will be to conditionally import the virtualfolder modules.


Resolving patch:
diff --git a/pootle/apps/pootle_store/forms.py b/pootle/apps/pootle_store/forms.py
--- a/pootle/apps/pootle_store/forms.py
+++ b/pootle/apps/pootle_store/forms.py
@@ -30,8 +30,6 @@
 from pootle_project.models import Project
 from pootle_statistics.models import (Submission, SubmissionFields,
                                       SubmissionTypes)
-from virtualfolder.helpers import extract_vfolder_from_path
-from virtualfolder.models import VirtualFolderTreeItem
 
 from .fields import to_db
 from .form_fields import (
@@ -514,6 +512,8 @@ def clean(self):
         self.cleaned_data["vfolder"] = None
         pootle_path = self.cleaned_data.get("path")
         if 'virtualfolder' in settings.INSTALLED_APPS:
+            from virtualfolder.helpers import extract_vfolder_from_path
+            from virtualfolder.models import VirtualFolderTreeItem
             vfolder, pootle_path = extract_vfolder_from_path(
                 pootle_path,
                 vfti=VirtualFolderTreeItem.objects.select_related(
diff --git a/pootle/apps/pootle_translationproject/views.py b/pootle/apps/pootle_translationproject/views.py
--- a/pootle/apps/pootle_translationproject/views.py
+++ b/pootle/apps/pootle_translationproject/views.py
@@ -28,9 +28,6 @@
 from pootle_app.views.admin.permissions import admin_permissions as admin_perms
 from pootle_language.models import Language
 from pootle_store.models import Store
-from virtualfolder.helpers import (
-    extract_vfolder_from_path, make_vfolder_treeitem_dict, vftis_for_child_dirs)
-from virtualfolder.models import VirtualFolderTreeItem
 
 from .models import TranslationProject
 
@@ -267,6 +264,7 @@ class TPBrowseView(TPDirectoryMixin, TPBrowseBaseView):
     @cached_property
     def items(self):
         if 'virtualfolder' in settings.INSTALLED_APPS:
+            from virtualfolder.helpers import vftis_for_child_dirs
             dirs_with_vfolders = set(
                 vftis_for_child_dirs(self.object).values_list(
                     "directory__pk", flat=True))
@@ -292,6 +290,7 @@ def has_vfolders(self):
 
     @cached_property
     def vfolders(self):
+        from virtualfolder.helpers import make_vfolder_treeitem_dict
         vftis = self.object.vf_treeitems
         if not self.has_admin_access:
             vftis = vftis.filter(vfolder__is_public=True)
@@ -365,6 +364,11 @@ def request_path(self):
 
     @cached_property
     def extracted_path(self):
+        if 'virtualfolder' not in settings.INSTALLED_APPS:
+            return None, self.request_path
+
+        from virtualfolder.helpers import extract_vfolder_from_path
+        from virtualfolder.models import VirtualFolderTreeItem
         return extract_vfolder_from_path(
             self.request_path,
             vfti=VirtualFolderTreeItem.objects.select_related(
diff --git a/pootle/core/decorators.py b/pootle/core/decorators.py
--- a/pootle/core/decorators.py
+++ b/pootle/core/decorators.py
@@ -8,6 +8,7 @@
 
 from functools import wraps
 
+from django.conf import settings
 from django.core.exceptions import PermissionDenied
 from django.core.urlresolvers import reverse
 from django.db import connection
@@ -22,7 +23,6 @@
 from pootle_project.models import Project, ProjectResource, ProjectSet
 from pootle_store.models import Store
 from pootle_translationproject.models import TranslationProject
-from virtualfolder.helpers import extract_vfolder_from_path
 
 from .exceptions import Http400
 from .url_helpers import split_pootle_path
@@ -132,11 +132,15 @@ def set_resource(request, path_obj, dir_path, filename):
 
     is_404 = False
 
-    # Get a clean pootle path for retrieving the directory or store.
-    # A clean pootle path is a pootle path without any virtual folder name on
-    # it. For example /af/test_vfolders/browser/chrome/ is the corresponding
-    # clean pootle path for /af/test_vfolders/browser/vfolder8/chrome/
-    vfolder, clean_pootle_path = extract_vfolder_from_path(pootle_path)
+    vfolder = None
+    clean_pootle_path = pootle_path
+    if 'virtualfolder' in settings.INSTALLED_APPS:
+        from virtualfolder.helpers import extract_vfolder_from_path
+        # Get a clean pootle path for retrieving the directory or store.
+        # A clean pootle path is a pootle path without any virtual folder name on
+        # it. For example /af/test_vfolders/browser/chrome/ is the corresponding
+        # clean pootle path for /af/test_vfolders/browser/vfolder8/chrome/
+        vfolder, clean_pootle_path = extract_vfolder_from_path(pootle_path)
 
     if filename:
         pootle_path = pootle_path + filename


Test patch: