#18979 closed Bug (fixed)
PermWrapper + template "if in" interaction
| Reported by: | Anssi Kääriäinen | Owned by: | Anssi Kääriäinen |
|---|---|---|---|
| Component: | Template system | Version: | 1.4 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Trying to do
{% if 'someperm' in perms.someapp %}has perm{% else %}no perm{% endif %}
will result in endless loop. Above, the perms is PermWrapper as installed by the RequestContext.
Doing if perms.someapp.someperm works correctly. I tried the above because I have a permission codename (from external database) which contains '-', so I can't use the documented syntax.
The attached tester project shows this error. run devserver, click the link, and you will have the dev-server in endless loop which isn't even killable by Ctrl-c... So, be prepared to kill the server by force.
I know the above isn't documented use of PermWrapper. But, to me it seems this bug isn't a PermWrapper bug, what it does looks sane to me. So, I am suspecting there could be some underlying bug in the template engine. So, I am marking this into Template system, though the bug could be elsewhere, too.
Tested with 1.4.1 and 1.5.dev20120918050907 with Python 2.7.3.
Attachments (1)
Change History (6)
by , 13 years ago
| Attachment: | test_project.tar.gz added |
|---|
comment:1 by , 13 years ago
comment:2 by , 13 years ago
| Owner: | changed from to |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
An irc-discussion with Alex, and the reason for this is now clear. The reason is that if there isn't __iter__ defined for an object, but it has a __getitem__ which never raises IndexError, then the 'something' in obj will continuously check for obj[i] == 'something'; i++...
The solution is to define an __iter__ which raises TypeError.
I am assigning this to myself. The only question is how to test this... A possible test would be to check False not in perms - the reason is that __getitem__ will return False for the first index, 0, and then the in check will see False in the perms incorrectly. And, there should be no possibility of forever-loop.
I am going to backpatch this to 1.4, too.
comment:3 by , 13 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
A patch is available in: https://github.com/akaariai/django/commit/ecb672bc6d9141e0b00a6ba4adf532340335040c
comment:4 by , 13 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
I am completely lost with this ticket... I replaced the contents of the some_view (testing/views.py) with this:
def some_view(request): context_instance=RequestContext(request) testing_perms = context_instance['perms']['testing'] 'foo' in testing_perms ret = render_to_response('a_template.html', {'foo': 'bar'}, context_instance=RequestContext(request)) return retThen, I placed a
print(__getitem__(%s) % perm_name)intodjango/contrib/auth/context_processors.py:PermLookupDict.__getitem__.. Access the view and it prints this endlessly:The stack trace is this:
^Cakaariai@akaariai-UX31E:~/Programming/tester$ python manage.py runserver Validating models... 0 errors found September 18, 2012 - 13:46:04 Django version 1.5.dev20120917231511, using settings 'tester.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C. __getitem__(0) > /home/akaariai/Programming/tester/django/contrib/auth/context_processors.py(14)__getitem__() -> return self.user.has_perm("%s.%s" % (self.module_name, perm_name)) (Pdb) perm_name 0 (Pdb) bt /usr/local/lib/python2.7/threading.py(524)__bootstrap() -> self.__bootstrap_inner() /usr/local/lib/python2.7/threading.py(551)__bootstrap_inner() -> self.run() /usr/local/lib/python2.7/threading.py(504)run() -> self.__target(*self.__args, **self.__kwargs) /usr/local/lib/python2.7/SocketServer.py(582)process_request_thread() -> self.finish_request(request, client_address) /usr/local/lib/python2.7/SocketServer.py(323)finish_request() -> self.RequestHandlerClass(request, client_address, self) /home/akaariai/Programming/tester/django/core/servers/basehttp.py(140)__init__() -> super(WSGIRequestHandler, self).__init__(*args, **kwargs) /usr/local/lib/python2.7/SocketServer.py(638)__init__() -> self.handle() /usr/local/lib/python2.7/wsgiref/simple_server.py(124)handle() -> handler.run(self.server.get_app()) /usr/local/lib/python2.7/wsgiref/handlers.py(85)run() -> self.result = application(self.environ, self.start_response) /home/akaariai/Programming/tester/django/contrib/staticfiles/handlers.py(71)__call__() -> return self.application(environ, start_response) /home/akaariai/Programming/tester/django/core/handlers/wsgi.py(236)__call__() -> response = self.get_response(request) /home/akaariai/Programming/tester/django/core/handlers/base.py(115)get_response() -> response = callback(request, *callback_args, **callback_kwargs) /home/akaariai/Programming/tester/testing/views.py(7)some_view() -> 'foo' in testing_perms > /home/akaariai/Programming/tester/django/contrib/auth/context_processors.py(14)__getitem__() -> return self.user.has_perm("%s.%s" % (self.module_name, perm_name))Tested both on Python 3.2 and Python 2.7, and at least 1.4.0 has this already.