Tuesday, March 4, 2014

Error starting django manage.py shell / runserver

So you're hacking away some django code for your next project and decide to test it out on runserver or in django's shell. But then you see this Error: No module named <module> - Not very helpful is it?

Next time this happens, try running runserver/shell (actually any django management command) with the --traceback option to figure out what is really going on.
./manage.py shell --traceback

Traceback (most recent call last):
  File "c:\Python27\lib\site-packages\django\core\management\base.py", line 217, in execute
    translation.activate('en-us')
  File "c:\Python27\lib\site-packages\django\utils\translation\__init__.py", line 105, in activate
    return _trans.activate(language)
  File "c:\Python27\lib\site-packages\django\utils\translation\trans_real.py", line 194, in activate
    _active.value = translation(language)
  File "c:\Python27\lib\site-packages\django\utils\translation\trans_real.py", line 183, in translation
    default_translation = _fetch(settings.LANGUAGE_CODE)
  File "c:\Python27\lib\site-packages\django\utils\translation\trans_real.py", line 160, in _fetch
    app = import_module(appname)
  File "c:\Python27\lib\site-packages\django\utils\importlib.py", line 35, in import_module
    __import__(name)
...
...
...
  File ".\project\models.py", line 2, in <module>
    from csv import DictWriter
ImportError: cannot import name DictWriter
models.py in the project app is importing the csv library which is supposed to be a standard library shipped with python. So now why is it missing features all of a sudden?
>>> import csv
>>> csv
<module 'csv' from 'csv.py'>
>>> import socket
>>> socket
<module 'socket' from 'c:\Python27\lib\socket.pyc'>
Importing csv.py in a separate python shell (not django shell) in the same folder revealed the cause - csv.py was being imported from the root of the project directory and not the usual place (C:\Python27\Lib\ on a windows machine). This one turned out to be just a dummy script that I was working on and for lack of a better name, just decided to call it csv.py. When manage.py scripts are running, it loads models.py's from all installed apps and in my case, one of them inadvertently loaded my custom csv.py, thus overriding the actual python library. This resulted in an ImportError in my case - could even  be something else like an AttributeError for you.

Errors like this can also happen because of cyclic imports (A imports B, B imports C, C imports A). To fix these, look at the traceback, figure out where the cycles are happening, and remove the problematic imports from the __main__ of the file - move these to wherever you are actually using it (like within a function). The interpreter will try running import statements inside functions only upon function invocation and not when the file is being read (unlike import statements in __main__/imports outside function bodies).
from app1.models import ModelA
def view1(request):
    return ModelA.objects.filter(user=request.user)
Instead, rewrite it like this.
def view1(request):
    from app1.models import ModelA
    return ModelA.objects.filter(user=request.user)

You don't have to worry about the performance penalty about re-importing the same module again and again because python loads modules and keeps them in memory inside a dict sys.modules, meaning the next time you try to import the same module, it sees that it's already got a copy with itself and doesn't repeat work.

window.ready vs window.load vs jQuery.ready() / DOMContentLoaded

DOMContentLoaded AKA jQuery.ready() is fired when the browser is done parsing the DOM, which includes script elements and iframes.

The load event is fired after DOMContentLoaded is fired. At this point, all resources are downloaded and ready which includes frames, images, etc. The browser's stop button stops spinning at this point.

index.html
<html>
    <head>
        <script type="text/javascript">
            console.log("HEAD_SCRIPT_INIT");
        </script>
    </head>
    <body>
        <script type="text/javascript">
            console.log("SCRIPT_TAG_1_INIT");
        </script>
        <script type="text/javascript">
            console.log("SCRIPT_TAG_2_INIT");
            document.addEventListener("DOMContentLoaded", function(){
                for(var i=0; i<10; i++)
                    console.log("SCRIPT_TAG_2_DOM_READY", i);
            });
            addEventListener("load", function(){
                console.log("SCRIPT2WINDOWLAOD");
            })
        </script>
        <iframe srcdoc='
            <script type="text/javascript">
                for(var i=0; i<10; i++)
                console.log("IFRAME_1_INIT:", i);
            </script>'>
        </iframe>
        <iframe srcdoc='
            <script type="text/javascript">
                for(var i=0; i<10; i++)
                    console.log("IFRAME_2_INIT:", i);
            </script>'>
        </iframe>
        <iframe src="iframe_3.html"></iframe>
        <iframe srcdoc='
            <script type="text/javascript">
                console.log("IFRAME_4_INIT");
                document.addEventListener("DOMContentLoaded", function(){
                    console.log("IFRAME_4_DOM_READY");
                })
                window.onload = function(){
                    console.log("IFRAME_4_WINDOW_ONLOAD");
                }
            </script>'>
        </iframe>
        <script async type="text/javascript" src="script_3.js"></script>
        <script type="text/javascript" src="script_4.js"></script>
        <script type="text/javascript">
            console.log("SCRIPT_TAG_5_INIT");
        </script>
        <script type="text/javascript">
            var script = document.createElement('script');
            script.innerText = 'console.log("HEAD_APPENDCHILD_INIT")';
            document.getElementsByTagName('head')[0].appendChild(script);
        </script>
        <script type="text/javascript">
            addEventListener("load", function(){
                console.log("SCRIPT7");
            })
        </script>
    </body>
</html>

iframe_3.html
<script type="text/javascript">
    console.log("IFRAME_3_INIT");
    document.addEventListener("DOMContentLoaded", function(){
        console.log("IFRAME_3_DOM_READY");
    })
    window.onload = function(){
        console.log("IFRAME_3_WINDOW_ONLOAD");
    }
</script>

script_3.js
console.log("SCRIPT_TAG_3_INIT");

script_4.js
console.log("SCRIPT_TAG_4_INIT");

Now, open index.html in a browser. Now open console and draw the following conclusions for yourself from our experiment.

As the downloaded html is parsed by the browser from top to bottom, any script tags in the head are executed followed by any script tags or iframe tags in the body.

Whether a script is specified inline or with an 'src' attribute, execution is done in order and it blocks parsing of the DOM unless the 'async' attribute is specified. 'async' scripts are downloaded out of order with respect to the other resources in the DOM. Downloading them will not block parsing the rest of the DOM, but they will block the load event during execution (it doesn't block DOMContentLoaded as far as I know).

Any script tags within iframe tags are parsed and executed right there if the content of the iframe is specified inline. If the iframe has an 'src' attribute, parsing of the DOM isn't blocked and the resource is downloaded in the background and executed when it's ready. Else it blocks further parsing. Also they fire their own DOMContentLoaded and load events and thus block the parents DOMContentLoaded and load events.

Iframes do not execute in parallel.

No script is EVER interrupted and execution is not switched to a different script just because an event was fired. The firing of every event blocks until the current block is done executing.

A script appended to head via JS code will be executed immediately (just like inline JS).