Repository: django-cms/django-cms

Issue:
Error in DefaultLanguageChanger when passing classes as views kwargs
When passing classes as kwargs to views in apphooked applications  (e.g.: `authentication_form` parameter to `django.contrib.auth.views.login`) DefaultLanguageChanger.**call** result in a traceback
Error is originated here
https://github.com/divio/django-cms/blame/develop/menus/utils.py#L133

Will try to come up with a test for this



Discussion:

Resolving patch:
diff --git a/menus/utils.py b/menus/utils.py
--- a/menus/utils.py
+++ b/menus/utils.py
@@ -128,6 +128,15 @@ def __call__(self, lang):
             if view.namespace:
                 "%s:%s" % (view.namespace, view_name)
             url = None
+            # every class-level argument is instantiated
+            # before reversing as reverse does not support
+            # classes as arguments
+            for idx, arg in enumerate(view.args):
+                if isinstance(arg, type):
+                    view.args[idx] = arg()
+            for key, arg in view.kwargs.items():
+                if isinstance(arg, type):
+                    view.kwargs[key] = arg()
             with force_language(lang):
                 try:
                     url = reverse(view_name, args=view.args, kwargs=view.kwargs, current_app=view.app_name)


Test patch:
diff --git a/cms/test_utils/project/sampleapp/forms.py b/cms/test_utils/project/sampleapp/forms.py
new file mode 100644
--- /dev/null
+++ b/cms/test_utils/project/sampleapp/forms.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+from django.contrib.auth.forms import AuthenticationForm
+
+
+class LoginForm(AuthenticationForm):
+    pass
+
+
+class LoginForm2(AuthenticationForm):
+    pass
diff --git a/cms/test_utils/project/sampleapp/templates/registration/login.html b/cms/test_utils/project/sampleapp/templates/registration/login.html
new file mode 100644
--- /dev/null
+++ b/cms/test_utils/project/sampleapp/templates/registration/login.html
@@ -0,0 +1,12 @@
+{% load cms_tags menu_tags %}
+<!DOCTYPE html>
+<html>
+<head lang="en">
+    <meta charset="UTF-8">
+    <title></title>
+</head>
+<body>
+<h1>{% page_language_url 'fr' %}</h1>
+{{form}}
+</body>
+</html>
\ No newline at end of file
diff --git a/cms/test_utils/project/urls.py b/cms/test_utils/project/urls.py
--- a/cms/test_utils/project/urls.py
+++ b/cms/test_utils/project/urls.py
@@ -1,11 +1,12 @@
-from cms.utils.conf import get_cms_setting
 from django.conf import settings
 from django.conf.urls import patterns, include, url
 from django.contrib import admin
 from django.conf.urls.i18n import i18n_patterns
+from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 
+from cms.utils.conf import get_cms_setting
+from cms.test_utils.project.sampleapp.forms import LoginForm, LoginForm2
 
-from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 
 admin.autodiscover()
 
@@ -21,6 +22,10 @@
 urlpatterns += staticfiles_urlpatterns()
 
 urlpatterns += i18n_patterns('',
+                             url(r'^sample/login_other/$', 'django.contrib.auth.views.login',
+                                 kwargs={'authentication_form': LoginForm2}),
+                             url(r'^sample/login/$', 'django.contrib.auth.views.login',
+                                 kwargs={'authentication_form': LoginForm}),
                              url(r'^admin/', include(admin.site.urls)),
                              url(r'^example/$', 'cms.test_utils.project.placeholderapp.views.example_view'),
                              url(r'^', include('cms.urls')),
diff --git a/cms/tests/menu_utils.py b/cms/tests/menu_utils.py
--- a/cms/tests/menu_utils.py
+++ b/cms/tests/menu_utils.py
@@ -1,20 +1,29 @@
+from django.http import HttpResponse
+
 from cms.test_utils.testcases import CMSTestCase
 from cms.test_utils.util.mock import AttributeObject
-from django.http import HttpResponse
 from menus.templatetags.menu_tags import PageLanguageUrl
-from menus.utils import (simple_language_changer, find_selected, 
-    language_changer_decorator)
+from menus.utils import (simple_language_changer, find_selected,
+                         language_changer_decorator)
 
 
 class DumbPageLanguageUrl(PageLanguageUrl):
     def __init__(self): pass
 
+
 class MenuUtilsTests(CMSTestCase):
     def get_simple_view(self):
         def myview(request):
             return HttpResponse('')
         return myview
-    
+
+    def test_reverse_in_changer(self):
+        response = self.client.get('/en/sample/login/')
+        self.assertContains(response, '<h1>/fr/sample/login/</h1>')
+
+        response = self.client.get('/en/sample/login_other/')
+        self.assertContains(response, '<h1>/fr/sample/login_other/</h1>')
+
     def test_simple_language_changer(self):
         func = self.get_simple_view()
         decorated_view = simple_language_changer(func)
@@ -63,8 +72,7 @@ def lang_changer(lang):
         output = tag.get_context(fake_context, 'ja')
         url = output['content']
         self.assertEqual(url, '/ja/dummy/')
-        
-        
+
     def test_find_selected(self):
         subchild = AttributeObject()
         firstchild = AttributeObject(ancestor=True, children=[subchild])