Commits

falsetru committed dfef809

Migrate to HRD.

Comments (0)

Files changed (21)

-application: ear
-version: 1
-api_version: 1
-runtime: python
-
-handlers:
-- url: /favicon.ico
-  static_files: static/images/favicon.ico
-  mime_type: image/vnd.microsoft.icon
-  upload: static/images/favicon.ico
-- url: /static
-  expiration: "30d"
-  static_dir: static
-- url: /load/script
-  script: loaders/script_loader.py
-- url: /load/dictlog
-  script: loaders/dictlog_loader.py
-- url: /load/dictlogmonthly
-  script: loaders/dictlogmonthly_loader.py
-- url: /update/.*
-  script: apps/update.py
-  login: admin
-- url: /edit/.*
-  script: apps/edit.py
-  login: admin
-- url: /download/.*
-  script: apps/download.py
-  login: admin
-- url: /tasks/.*
-  script: apps/tasks.py
-- url: /test.*
-  script: gaeunit.py
-- url: /.*
-  script: apps/main.py
+application: ear-hrd
+version: 1
+api_version: 1
+runtime: python27
+threadsafe: false
+
+libraries:
+- name: django
+  version: 1.2
+
+handlers:
+- url: /favicon.ico
+  static_files: static/images/favicon.ico
+  mime_type: image/vnd.microsoft.icon
+  upload: static/images/favicon.ico
+- url: /static
+  expiration: "30d"
+  static_dir: static
+- url: /update/.*
+  script: apps.update.app
+  login: admin
+- url: /edit/.*
+  script: apps.edit.app
+  login: admin
+- url: /tasks/.*
+  script: apps.tasks.app
+- url: /test.*
+  script: gaeunit.app
+- url: /.*
+  script: apps.main.app

apps/custom_tags.py

 import urllib
 from google.appengine.ext import webapp
+from google.appengine._internal.django.utils.safestring import mark_safe
 register = webapp.template.create_template_register()
 
 def _embed(media_url, autoplay):
         return r'''<embed src="%(url)s" autoplay="%(autoplay)s" autostart="%(autoplay)s" width="300" height="50" loop="true" repeat="true" />''' % dict(url=media_url, autoplay=("true" if autoplay else "false"))
         
 @register.filter
-def embed(media_url): return _embed(media_url, autoplay=1)
+def embed(media_url): return mark_safe(_embed(media_url, autoplay=1))
 
 @register.filter
-def embed_no_autoplay(media_url): return _embed(media_url, autoplay=0)
+def embed_no_autoplay(media_url): return mark_safe(_embed(media_url, autoplay=0))
         
 
 @register.filter
 def bar(width):
-    return '<img src="/static/images/dot.png" width="%s" height="10" />' % width
+    return mark_safe('<img src="/static/images/dot.png" width="%s" height="10" />' % width)

apps/download.py

-#!/usr/bin/env python
-
-import wsgiref.handlers
-from google.appengine.ext import webapp
-from models import DictLog
-import csv
-
-class DailyDictLogDownloadPage(webapp.RequestHandler):
-    def get(self, modelname):
-        # XXX respect modelname
-        self.response.headers['Content-type'] = 'text/csv; charset=utf-8'
-        self.response.headers['Content-disposition'] = \
-                'attachment; filename=dictlog-daily.csv'
-        writer = csv.writer(self.response.out)
-        for dictlog in DictLog.all():
-            writer.writerow([
-                dictlog.created,
-                dictlog.user.email(),
-                dictlog.dictcount,
-                dictlog.chrs,
-                dictlog.secs])
-
-def main():
-    application = webapp.WSGIApplication([
-            (r'/download/(dictlog)/?', DailyDictLogDownloadPage),
-        ], debug=True)
-    wsgiref.handlers.CGIHandler().run(application)
-
-if __name__ == '__main__':
-    main()
 from google.appengine.api import memcache
 from apps.update import download
 from tools.getscript2 import GMNLink
+import webapp2
 
 class ScriptEditPage(webapp.RequestHandler):
     def init(self, key_name):
 
     def display_form(self):
         self.response.out.write(
-            template.render('templates/edit.html',
+            template.render('apps/templates/edit.html',
                 {'script': self.script}))
 
     def get(self, key_name):
         memcache.delete('listing')
         self.redirect('/')
         
-def main():
-    application = webapp.WSGIApplication([
-            (r'/edit/([-\w]+)/?', ScriptEditPage),
-            (r'/edit/([-\w]+)/regenerate/?', ScriptRegeneratePage),
-            (r'/edit/([-\w]+)/delete/?', ScriptDeletePage),
-        ], debug=True)
-    wsgiref.handlers.CGIHandler().run(application)
-
-if __name__ == '__main__':
-    main()
+app = webapp2.WSGIApplication([
+        (r'/edit/([-\w]+)/?', ScriptEditPage),
+        (r'/edit/([-\w]+)/regenerate/?', ScriptRegeneratePage),
+        (r'/edit/([-\w]+)/delete/?', ScriptDeletePage),
+    ], debug=True)
 #!/usr/bin/env python
 
+from django.utils.safestring import mark_safe
+
 import wsgiref.handlers
 from google.appengine.ext import webapp
 from google.appengine.ext.webapp import template
 from google.appengine.api import users
 from models import *
 from models_mixin import fill_blank_dates
-import random
 import datetime
 from apps import googlechartapi
 import urllib
 from collections import defaultdict
 from google.appengine.api import memcache
-from apps.quiz import *
+import sys
 webapp.template.register_template_library('apps.custom_tags')
+import webapp2
 
 def login_logout_link(dest_url='/'):
     user = users.get_current_user()
         user = users.get_current_user()
         listing = memcache.get('listing')
         if listing is None:
-            listing = template.render('templates/listing.html',
+            listing = template.render('apps/templates/listing.html',
                 {'scripts': Script.all().order('title')})
             memcache.set('listing', listing)
 
-        self.response.out.write(
-            template.render('templates/frontpage.html',
-                {'listing': listing,
-                 'login_logout_link': login_logout_link(),
-                 'is_admin': users.is_current_user_admin(),
-                 'user': user,}))
+        html = template.render('apps/templates/frontpage.html', {
+            'listing': listing,
+            'login_logout_link': mark_safe(login_logout_link()),
+            'is_admin': users.is_current_user_admin(),
+            'user': user,
+            'version': sys.version,
+        })
+        self.response.out.write(str(html))
 
 class DictationPage(webapp.RequestHandler):
     def get(self, key_name=None):
         autoplay = self.request.get('autoplay', '1')
         autoplay = autoplay == '1'
-        if key_name == 'random':
-            total = Script.all().count()
-            i = random.randint(0, total-1)
-            script = Script.all().fetch(1, offset=i)[0]
-            self.redirect('/dictation/%s?autoplay=%s' % (script.key().name(), autoplay))
-            return
         script = Script.get_by_key_name(key_name)
         user = users.get_current_user()
-        self.response.out.write(template.render('templates/dictation.html', {
+        self.response.out.write(template.render('apps/templates/dictation.html', {
             'script': script, 'user': user, 'key_name': key_name,
             'is_admin': users.is_current_user_admin(),
             'autoplay': autoplay
         user = user_from_email(email)
         if user:
             self.response.out.write(
-                template.render('templates/records.html',
+                template.render('apps/templates/records.html',
                     {'chart_url': self.chart_url(user), 'user': user}
                 )
             )
             now.strftime('%Y-%m-%d')))
         today_dictcount = todaylog.dictcount if todaylog else 0
         self.response.out.write(
-            template.render('templates/records/score.html', {
+            template.render('apps/templates/score.html', {
                 'logs': logs,
                 'today_dictcount': today_dictcount,
             })
         UserDictLog.delete_score(logkey, users.get_current_user())
         self.response.out.write('OK')
 
-class QuizPage(webapp.RequestHandler):
-    def _random_index(self, nchoice):
-        total = Script.all().count()
-        return random.randint(0, total-1-nchoice)
 
-    def get(self, nchoice=5):
-        scripts = Script.all().fetch(nchoice,
-            offset=self._random_index(nchoice))
-        q = ChoiceQuiz.from_scripts(scripts)
-        self.response.out.write(
-            template.render('templates/quiz.html',
-                {'quiz': q})
-        )
-
-def main():
-    application = webapp.WSGIApplication([
-            (r'/', ListingPage),
-            (r'/dictation/([-\w]+)/?', DictationPage),
-            (r'/completed/?', RecordCompletionService),
-            (r'/record/daily/(?P<email>[^/]+)/?', DailyRecordPage),
-            (r'/record/monthly/(?P<email>[^/]+)/?', MonthlyRecordPage),
-            (r'/record/daily/?', DailyRecordPage),
-            (r'/record/monthly/?', MonthlyRecordPage),
-            (r'/record/score/?', ScoreRecordPage),
-            (r'/record/score/(?P<logkey>[^/]+)/delete/?', ScoreRecordDeletePage),
-            (r'/quiz/?', QuizPage),
-        ], debug=True)
-    wsgiref.handlers.CGIHandler().run(application)
-
-if __name__ == '__main__':
-    main()
+app = webapp2.WSGIApplication([
+        (r'/', ListingPage),
+        (r'/dictation/([-\w]+)/?', DictationPage),
+        (r'/completed/?', RecordCompletionService),
+        (r'/record/daily/(?P<email>[^/]+)/?', DailyRecordPage),
+        (r'/record/monthly/(?P<email>[^/]+)/?', MonthlyRecordPage),
+        (r'/record/daily/?', DailyRecordPage),
+        (r'/record/monthly/?', MonthlyRecordPage),
+        (r'/record/score/?', ScoreRecordPage),
+        (r'/record/score/(?P<logkey>[^/]+)/delete/?', ScoreRecordDeletePage),
+    ], debug=True)

apps/quiz.py

-import random
-
-class ChoiceQuiz:
-
-    def __init__(self, question, choices):
-        self.question = question
-        self.choices = choices
-
-    def __len__(self):
-        return len(self.choices)
-
-    def __getitem__(self, i):
-        return self.choices[i]
-
-    def shuffle(self):
-        random.shuffle(self.choices)
-
-    @classmethod
-    def from_scripts(cls, scripts):
-        questions = []
-        for i, script in enumerate(scripts):
-            q = cls(script.mp3url,
-                [Choice(s, i == j) for j, s in enumerate(scripts)])
-            questions.append(q)
-        return random.choice(questions)
-
-
-class Choice:
-
-    def __init__(self, script, correct):
-        self.script = script
-        self.correct = correct
-
-    def __str__(self):
-        return self.script.title.split(':', 1)[-1].strip()
 from google.appengine.ext import webapp
 from models import *
 import datetime
+import webapp2
 
 class LogDeletionTask(webapp.RequestHandler):
     def get(self):
         DictLog.delete_old(datetime.date.today(), 31)
         self.response.out.write('OK')
 
-def main():
-    application = webapp.WSGIApplication([
-            (r'/tasks/delete/dictlog/?', LogDeletionTask),
-        ], debug=True)
-    wsgiref.handlers.CGIHandler().run(application)
-
-if __name__ == '__main__':
-    main()
+app = webapp2.WSGIApplication([
+        (r'/tasks/delete/dictlog/?', LogDeletionTask),
+    ], debug=True)

apps/templates/frontpage.html

 
 {% block content %}
 <ul>
-    <li>{{ login_logout_link }}</li>
+    <li>{{ login_logout_link|safe }}</li>
 {% if is_admin %}
     <li><a href="/update/gmpnews/3">Update GMPNews scripts</a> /
         <a href="/update/gmpnews-by-msgid/">Update GMPNews by msgid</a> /
         <a href="/record/score">score by script</a> /
     )</li>
 {% endif %}
-    <li><a href="/quiz">Quiz</a></li>
+    <li>{{ version }}</li>
 
 </ul>
-{{ listing }}
+{{ listing|safe }}
 {% endblock %}

apps/templates/listing.html

 <ul>
-    <li><a href="/dictation/random">Random script</a></li>
 {% regroup scripts by month as lst %}
 
 {% for month in lst %}

apps/templates/quiz.html

-{% extends "base.html" %}
-
-{% block title %}Quiz{% endblock %}
-{% block javascripts %}
-<script>
-    function check(is_correct) {
-        if (is_correct) {
-            document.getElementById('correct').innerHTML = 'Correct <a href="/quiz">Another Quiz</a>';
-        } else {
-            document.getElementById('correct').innerHTML = 'Wrong';
-        }
-        return true;
-    }
-</script>
-{% endblock %}
-{% block content %}
-
-<h1>Select appropriate title for the news script.</h1>
-
-{{ quiz.question|embed }}
-
-{% for choice in quiz.choices %}
-<p>
-    <input type="radio" name="answer"
-        onclick="check({{ choice.correct|lower }})" />
-        {{ choice|stringformat:"s" }} [<a href="{{ choice.script.dict_url }}">Dictation</a>]
-</p>
-{% endfor %}
-<h2 id="correct"></h2>
-{% endblock %}
-

apps/templates/records/score.html

-{% extends "../base.html" %}
-
-{% block javascripts %}
-<script type="text/javascript" src="/static/js/jquery.tablesorter.js"></script> 
-<script type="text/javascript" src="/static/js/apps/score.js"></script>
-<script>
-    function remove_row(url, rowid) {
-        $('#' + rowid + ' .loading').show();
-        $.ajax({
-            'url': url,
-            'type': 'POST',
-            'complete': function() {
-                $('#' + rowid + ' .loading').hide();
-            },
-            'success': function() {
-                $('#' + rowid).remove();
-            }
-        });
-    }
-</script>
-{% endblock %}
-
-{% block content %}
-<table id="records" class="tablesorter">
-    <thead>
-    <tr>
-        <th>-</th>
-        <th>-</th>
-        <th>last try</th>
-        <th>count</th>
-        <th>record</th>
-        <th></th>
-    </tr>
-    </thead>
-    <tbody>
-{% for log in logs %}
-    <tr id="{{ log.created }}" onmouseover="$(this).addClass('mouseover')" onmouseout="$(this).removeClass('mouseover')">
-        <td><a href="#" onclick="remove_row('{{ log.delurl }}', '{{ log.created }}'); return false">delete</a>
-            <img src="/static/images/loading.gif" class="loading" style="display: none"/></td>
-        <td><a href="{{ log.dicturl }}" onclick="dodict($(this))">{{log.created}}</a></td>
-        <td>{{log.updated|date:"Y-m-d H:i:s"}}</td>
-        <td align="right">{{log.dictcount}}</td>
-        <td align="right">{{log.cps|floatformat:2}}</td>
-        <td>{{log.percentage|bar}}</td>
-    </tr>
-{% endfor %}
-    </tbody>
-</table>
-<span id="clickcount">{{ today_dictcount }}</span>
-{% endblock %}

apps/templates/score.html

+{% extends "base.html" %}
+
+{% block javascripts %}
+<script type="text/javascript" src="/static/js/jquery.tablesorter.js"></script> 
+<script type="text/javascript" src="/static/js/apps/score.js"></script>
+<script>
+    function remove_row(url, rowid) {
+        $('#' + rowid + ' .loading').show();
+        $.ajax({
+            'url': url,
+            'type': 'POST',
+            'complete': function() {
+                $('#' + rowid + ' .loading').hide();
+            },
+            'success': function() {
+                $('#' + rowid).remove();
+            }
+        });
+    }
+</script>
+{% endblock %}
+
+{% block content %}
+<table id="records" class="tablesorter">
+    <thead>
+    <tr>
+        <th>-</th>
+        <th>-</th>
+        <th>last try</th>
+        <th>count</th>
+        <th>record</th>
+        <th></th>
+    </tr>
+    </thead>
+    <tbody>
+{% for log in logs %}
+    <tr id="{{ log.created }}" onmouseover="$(this).addClass('mouseover')" onmouseout="$(this).removeClass('mouseover')">
+        <td><a href="#" onclick="remove_row('{{ log.delurl }}', '{{ log.created }}'); return false">delete</a>
+            <img src="/static/images/loading.gif" class="loading" style="display: none"/></td>
+        <td><a href="{{ log.dicturl }}" onclick="dodict($(this))">{{log.created}}</a></td>
+        <td>{{log.updated|date:"Y-m-d H:i:s"}}</td>
+        <td align="right">{{log.dictcount}}</td>
+        <td align="right">{{log.cps|floatformat:2}}</td>
+        <td>{{log.percentage|bar}}</td>
+    </tr>
+{% endfor %}
+    </tbody>
+</table>
+<span id="clickcount">{{ today_dictcount }}</span>
+{% endblock %}

apps/templates/update-by-msgid.html

 <form method="post" action="">
     msgid: <input type="text" name="msgid" size="80" />
     <input type="submit" value="Update" />
+    <p>(msgid: http://kbbs.kbs.co.kr/board/message/view.do?boardName=2fm_lgcgmp_vboard18&messageId=<b>32331268</b>)<p>
+    <p>If you have the script already. This will not work.</p>
 </form>
 {% endblock %}
 
 from google.appengine.api import urlfetch
 from google.appengine.api import memcache
 import itertools
+import webapp2
 
 def download(url):
     result = urlfetch.fetch(url)
 class GMPNewsUpdateByMsgIdPage(webapp.RequestHandler):
     def get(self):
         self.response.out.write(
-            template.render('templates/update-by-msgid.html', {
+            template.render('apps/templates/update-by-msgid.html', {
             })
         )
     def post(self):
         memcache.delete('listing')
         self.redirect('/')
 
-def main():
-    application = webapp.WSGIApplication([
-        (r'/update/gmpnews/(?P<count>\d+)/?', GMPNewsUpdatePage),
-        (r'/update/gmpnews-by-msgid/?', GMPNewsUpdateByMsgIdPage),
-        (r'/update/delete-cache/?', GMPNewsDeleteListingCache),
-    ], debug=True)
-    wsgiref.handlers.CGIHandler().run(application)
-
-if __name__ == '__main__':
-    main()
+app = webapp2.WSGIApplication([
+    (r'/update/gmpnews/(?P<count>\d+)/?', GMPNewsUpdatePage),
+    (r'/update/gmpnews-by-msgid/?', GMPNewsUpdateByMsgIdPage),
+    (r'/update/delete-cache/?', GMPNewsDeleteListingCache),
+], debug=True)
 3. Launch the development web server.  To run all tests, point your browser to:
 
    http://localhost:8080/test     (Modify the port if necessary.)
-   
+
    For plain text output add '?format=plain' to the above URL.
    See README.TXT for information on how to run specific tests.
 
 import unittest
 import time
 import logging
-import cgi
-import django.utils.simplejson
 
 from google.appengine.ext import webapp
-from google.appengine.api import apiproxy_stub_map  
+from google.appengine.api import apiproxy_stub_map
 from google.appengine.api import datastore_file_stub
-from google.appengine.ext.webapp.util import run_wsgi_app
 
 _LOCAL_TEST_DIR = 'test'  # location of files
 _WEB_TEST_DIR = '/test'   # how you want to refer to tests on your web server
 class MainTestPageHandler(webapp.RequestHandler):
     def get(self):
         unknown_args = [arg for arg in self.request.arguments()
-                        if arg not in ("format", "package", "name")]
+                        if arg not in ("package", "name")]
         if len(unknown_args) > 0:
             errors = []
             for arg in unknown_args:
             self.response.out.write(" ".join(errors))
             return
 
-        format = self.request.get("format", "html")
-        if format == "html":
-            self._render_html()
-        elif format == "plain":
-            self._render_plain()
-        else:
-            error = _log_error("The format '%s' is not valid." % cgi.escape(format))
-            self.error(404)
-            self.response.out.write(error)
-            
-    def _render_html(self):
-        suite, error = _create_suite(self.request)
-        if not error:
-            self.response.out.write(_MAIN_PAGE_CONTENT % (_test_suite_to_json(suite), _WEB_TEST_DIR, __version__))
-        else:
-            self.error(404)
-            self.response.out.write(error)
-        
+        self._render_plain()
+
     def _render_plain(self):
         self.response.headers["Content-Type"] = "text/plain"
+        self.response.out.flush = lambda: 0
         runner = unittest.TextTestRunner(self.response.out)
         suite, error = _create_suite(self.request)
         if not error:
-            self.response.out.write("====================\n" \
-                                    "GAEUnit Test Results\n" \
-                                    "====================\n\n")
             _run_test_suite(runner, suite)
         else:
             self.error(404)
             self.response.out.write(error)
 
-
-##############################################################################
-# JSON test classes
-##############################################################################
-
-
-class JsonTestResult(unittest.TestResult):
-    def __init__(self):
-        unittest.TestResult.__init__(self)
-        self.testNumber = 0
-
-    def render_to(self, stream):
-        result = {
-            'runs': self.testsRun,
-            'total': self.testNumber,
-            'errors': self._list(self.errors),
-            'failures': self._list(self.failures),
-            }
-
-        stream.write(django.utils.simplejson.dumps(result).replace('},', '},\n'))
-
-    def _list(self, list):
-        dict = []
-        for test, err in list:
-            d = { 
-              'desc': test.shortDescription() or str(test), 
-              'detail': err,
-            }
-            dict.append(d)
-        return dict
-
-
-class JsonTestRunner:
-    def run(self, test):
-        self.result = JsonTestResult()
-        self.result.testNumber = test.countTestCases()
-        startTime = time.time()
-        test(self.result)
-        stopTime = time.time()
-        timeTaken = stopTime - startTime
-        return self.result
-
-
-class JsonTestRunHandler(webapp.RequestHandler):
-    def get(self):    
-        self.response.headers["Content-Type"] = "text/javascript"
-        test_name = self.request.get("name")
-        _load_default_test_modules()
-        suite = unittest.defaultTestLoader.loadTestsFromName(test_name)
-        runner = JsonTestRunner()
-        _run_test_suite(runner, suite)
-        runner.result.render_to(self.response.out)
-
-
-# This is not used by the HTML page, but it may be useful for other client test runners.
-class JsonTestListHandler(webapp.RequestHandler):
-    def get(self):
-        self.response.headers["Content-Type"] = "text/javascript"
-        suite, error = _create_suite(self.request)
-        if not error:
-            self.response.out.write(_test_suite_to_json(suite))
-        else:
-            self.error(404)
-            self.response.out.write(error)
-
-
 ##############################################################################
 # Module helper functions
 ##############################################################################
 
     try:
         if not package_name and not test_name:
-                modules = _load_default_test_modules()
-                for module in modules:
-                    suite.addTest(loader.loadTestsFromModule(module))
+            modules = _load_default_test_modules()
+            for module in modules:
+                suite.addTest(loader.loadTestsFromModule(module))
         elif test_name:
-                _load_default_test_modules()
-                suite.addTest(loader.loadTestsFromName(test_name))
+            _load_default_test_modules()
+            suite.addTest(loader.loadTestsFromName(test_name))
         elif package_name:
-                package = reload(__import__(package_name))
-                module_names = package.__all__
-                for module_name in module_names:
-                    suite.addTest(loader.loadTestsFromName('%s.%s' % (package_name, module_name)))
-    
+            package = reload(__import__(package_name))
+            module_names = package.__all__
+            for module_name in module_names:
+                suite.addTest(loader.loadTestsFromName('%s.%s' % (package_name, module_name)))
+
         if suite.countTestCases() == 0:
             raise Exception("'%s' is not found or does not contain any tests." %  \
                             (test_name or package_name or 'local directory: \"%s\"' % _LOCAL_TEST_DIR))
     module_names = [mf[0:-3] for mf in os.listdir(_LOCAL_TEST_DIR) if mf.endswith(".py")]
     return [reload(__import__(name)) for name in module_names]
 
-
-def _get_tests_from_suite(suite, tests):
-    for test in suite:
-        if isinstance(test, unittest.TestSuite):
-            _get_tests_from_suite(test, tests)
-        else:
-            tests.append(test)
-
-
-def _test_suite_to_json(suite):
-    tests = []
-    _get_tests_from_suite(suite, tests)
-    test_tuples = [(type(test).__module__, type(test).__name__, test._testMethodName) \
-                   for test in tests]
-    test_dict = {}
-    for test_tuple in test_tuples:
-        module_name, class_name, method_name = test_tuple
-        if module_name not in test_dict:
-            mod_dict = {}
-            method_list = []
-            method_list.append(method_name)
-            mod_dict[class_name] = method_list
-            test_dict[module_name] = mod_dict
-        else:
-            mod_dict = test_dict[module_name]
-            if class_name not in mod_dict:
-                method_list = []
-                method_list.append(method_name)
-                mod_dict[class_name] = method_list
-            else:
-                method_list = mod_dict[class_name]
-                method_list.append(method_name)
-                
-    return django.utils.simplejson.dumps(test_dict)
-
-
 def _run_test_suite(runner, suite):
     """Run the test suite.
 
     test suite, run the test suite, and restore the development apiproxy.
     This isolates the test datastore from the development datastore.
 
-    """        
+    """
     original_apiproxy = apiproxy_stub_map.apiproxy
     try:
-       apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap() 
-       temp_stub = datastore_file_stub.DatastoreFileStub('GAEUnitDataStore', None, None, trusted=True)  
+       apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
+       temp_stub = datastore_file_stub.DatastoreFileStub('GAEUnitDataStore', None, None, trusted=True)
        apiproxy_stub_map.apiproxy.RegisterStub('datastore', temp_stub)
        # Allow the other services to be used as-is for tests.
-       for name in ['user', 'urlfetch', 'mail', 'memcache', 'images']: 
+       for name in ['user', 'urlfetch', 'mail', 'memcache', 'images']:
            apiproxy_stub_map.apiproxy.RegisterStub(name, original_apiproxy.GetStub(name))
        runner.run(suite)
     finally:
    logging.warn(s)
    return s
 
-           
-################################################
-# Browser HTML, CSS, and Javascript
-################################################
-
-
-# This string uses Python string formatting, so be sure to escape percents as %%.
-_MAIN_PAGE_CONTENT = """
-<html>
-<head>
-    <style>
-        body {font-family:arial,sans-serif; text-align:center}
-        #title {font-family:"Times New Roman","Times Roman",TimesNR,times,serif; font-size:28px; font-weight:bold; text-align:center}
-        #version {font-size:87%%; text-align:center;}
-        #weblink {font-style:italic; text-align:center; padding-top:7px; padding-bottom:7px}
-        #results {padding-top:20px; margin:0pt auto; text-align:center; font-weight:bold}
-        #testindicator {width:750px; height:16px; border-style:solid; border-width:2px 1px 1px 2px; background-color:#f8f8f8;}
-        #footerarea {text-align:center; font-size:83%%; padding-top:25px}
-        #errorarea {padding-top:25px}
-        .error {border-color: #c3d9ff; border-style: solid; border-width: 2px 1px 2px 1px; width:750px; padding:1px; margin:0pt auto; text-align:left}
-        .errtitle {background-color:#c3d9ff; font-weight:bold}
-    </style>
-    <script language="javascript" type="text/javascript">
-        var testsToRun = %s;
-        var totalRuns = 0;
-        var totalErrors = 0;
-        var totalFailures = 0;
-
-        function newXmlHttp() {
-          try { return new XMLHttpRequest(); } catch(e) {}
-          try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
-          try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
-          alert("XMLHttpRequest not supported");
-          return null;
-        }
-        
-        function requestTestRun(moduleName, className, methodName) {
-            var methodSuffix = "";
-            if (methodName) {
-                methodSuffix = "." + methodName;
-            }
-            var xmlHttp = newXmlHttp();
-            xmlHttp.open("GET", "%s/run?name=" + moduleName + "." + className + methodSuffix, true);
-            xmlHttp.onreadystatechange = function() {
-                if (xmlHttp.readyState != 4) {
-                    return;
-                }
-                if (xmlHttp.status == 200) {
-                    var result = eval("(" + xmlHttp.responseText + ")");
-                    totalRuns += parseInt(result.runs);
-                    totalErrors += result.errors.length;
-                    totalFailures += result.failures.length;
-                    document.getElementById("testran").innerHTML = totalRuns;
-                    document.getElementById("testerror").innerHTML = totalErrors;
-                    document.getElementById("testfailure").innerHTML = totalFailures;
-                    if (totalErrors == 0 && totalFailures == 0) {
-                        testSucceed();
-                    } else {
-                        testFailed();
-                    }
-                    var errors = result.errors;
-                    var failures = result.failures;
-                    var details = "";
-                    for(var i=0; i<errors.length; i++) {
-                        details += '<p><div class="error"><div class="errtitle">ERROR ' +
-                                   errors[i].desc +
-                                   '</div><div class="errdetail"><pre>'+errors[i].detail +
-                                   '</pre></div></div></p>';
-                    }
-                    for(var i=0; i<failures.length; i++) {
-                        details += '<p><div class="error"><div class="errtitle">FAILURE ' +
-                                    failures[i].desc +
-                                    '</div><div class="errdetail"><pre>' +
-                                    failures[i].detail +
-                                    '</pre></div></div></p>';
-                    }
-                    var errorArea = document.getElementById("errorarea");
-                    errorArea.innerHTML += details;
-                } else {
-                    document.getElementById("errorarea").innerHTML = xmlHttp.responseText;
-                    testFailed();
-                }
-            };
-            xmlHttp.send(null);            
-        }
-
-        function testFailed() {
-            document.getElementById("testindicator").style.backgroundColor="red";
-        }
-        
-        function testSucceed() {
-            document.getElementById("testindicator").style.backgroundColor="green";
-        }
-        
-        function runTests() {
-            // Run each test asynchronously (concurrently).
-            var totalTests = 0;
-            for (var moduleName in testsToRun) {
-                var classes = testsToRun[moduleName];
-                for (var className in classes) {
-                    // TODO: Optimize for the case where tests are run by class so we don't
-                    //       have to always execute each method separately.  This should be
-                    //       possible when we have a UI that allows the user to select tests
-                    //       by module, class, and method.
-                    //requestTestRun(moduleName, className);
-                    methods = classes[className];
-                    for (var i = 0; i < methods.length; i++) {
-                        totalTests += 1;
-                        var methodName = methods[i];
-                        requestTestRun(moduleName, className, methodName);
-                    }
-                }
-            }
-            document.getElementById("testtotal").innerHTML = totalTests;
-        }
-
-    </script>
-    <title>GAEUnit: Google App Engine Unit Test Framework</title>
-</head>
-<body onload="runTests()">
-    <div id="headerarea">
-        <div id="title">GAEUnit: Google App Engine Unit Test Framework</div>
-        <div id="version">Version %s</div>
-    </div>
-    <div id="resultarea">
-        <table id="results"><tbody>
-            <tr><td colspan="3"><div id="testindicator"> </div></td</tr>
-            <tr>
-                <td>Runs: <span id="testran">0</span>/<span id="testtotal">0</span></td>
-                <td>Errors: <span id="testerror">0</span></td>
-                <td>Failures: <span id="testfailure">0</span></td>
-            </tr>
-        </tbody></table>
-    </div>
-    <div id="errorarea"></div>
-    <div id="footerarea">
-        <div id="weblink">
-        <p>
-            Please visit the <a href="http://code.google.com/p/gaeunit">project home page</a>
-            for the latest version or to report problems.
-        </p>
-        <p>
-            Copyright 2008-2009 <a href="mailto:George.Z.Lei@Gmail.com">George Lei</a>
-            and <a href="mailto:srfarley@gmail.com>Steven R. Farley</a>
-        </p>
-        </div>
-    </div>
-</body>
-</html>
-"""
-
 
 ##############################################################################
 # Script setup and execution
 ##############################################################################
 
 
-application = webapp.WSGIApplication([('%s'      % _WEB_TEST_DIR, MainTestPageHandler),
-                                      ('%s/run'  % _WEB_TEST_DIR, JsonTestRunHandler),
-                                      ('%s/list' % _WEB_TEST_DIR, JsonTestListHandler)],
-                                      debug=True)
-
-def main():
-    run_wsgi_app(application)                                    
-
-if __name__ == '__main__':
-    main()
+app = webapp.WSGIApplication([
+    ('%s'      % _WEB_TEST_DIR, MainTestPageHandler),
+], debug=True)
 #!/usr/bin/python
 
 import subprocess, sys
-url = 'http://localhost:8080/test?format=plain'
+url = 'http://localhost:8080/test'
 if sys.platform == 'win32':
-    subprocess.call([sys.executable, '-m', 'contest.main', sys.executable, '-m', 'urllib', url])
+    subprocess.call(['c', 'py,html', sys.executable, '-m', 'urllib', url])
 else:
-    subprocess.call([sys.executable, '-m', 'contest.main', 'wget', '-q', '-O-', url])
+    subprocess.call(['c', 'py,html', 'wget', '-q', '-O-', url])

loaders/dictlog_loader.py

-from google.appengine.ext import bulkload
-from google.appengine.api import users
-from google.appengine.api import datastore
-from models import *
-
-class DictLogLoader(bulkload.Loader):
-    def __init__(self, kind):
-        bulkload.Loader.__init__(self, kind, [
-            ('created', str),
-            ('user', users.User),
-            ('dictcount', int),
-            ('chrs', int),
-            ('secs', float),
-        ])
-
-    def HandleEntity(self, entity):
-        newent = datastore.Entity(self.kind(),
-                name='%s-%s-%s' % (
-                    self.kind(), entity['user'].email(), entity['created']))
-        newent.update(entity)
-        return newent
-
-def main(kind):
-    bulkload.main(DictLogLoader(kind))
-
-if __name__ == '__main__':
-    main('DictLog')

loaders/dictlogmonthly_loader.py

-from google.appengine.ext import bulkload
-from dictlog_loader import DictLogLoader
-
-if __name__ == '__main__':
-    bulkload.main(DictLogLoader('DictLogMonthly'))

loaders/script_loader.py

-from google.appengine.ext import bulkload
-from google.appengine.api import datastore_types
-from google.appengine.api import datastore
-from google.appengine.api import memcache
-from models import *
-
-class ScriptLoader(bulkload.Loader):
-    def __init__(self):
-        bulkload.Loader.__init__(self, 'Script',
-            [
-                ('key_name', str),
-                ('title', str),
-                ('content', str),
-                ('mp3url', datastore_types.Link),
-                ('srcurl', datastore_types.Link),
-            ]
-        )
-
-    def HandleEntity(self, entity):
-        if Script.get_by_key_name(entity['key_name']):
-            # Disallow duplication
-            return []
-        newent = datastore.Entity('Script', name=entity['key_name'])
-        del entity['key_name']
-        newent.update(entity)
-        return newent
-
-if __name__ == '__main__':
-    memcache.delete('listing')
-    bulkload.main(ScriptLoader())

test/test_apps.py

 
 class AppsTest(unittest.TestCase):
     def test_existence(self):
-        import apps.download
         import apps.edit
         import apps.main
-        import apps.quiz
         import apps.update
 
 if __name__ == '__main__':

test/test_quiz.py

-import unittest
-from apps.quiz import *
-
-
-class ChoiceQuizTest(unittest.TestCase):
-    def test_choice_correctness(self):
-        q = ChoiceQuiz('Selection largest number',
-            [Choice(MockScript('1', '1.mp3'), False),
-             Choice(MockScript('2', '2.mp3'), False),
-             Choice(MockScript('3', '3.mp3'), False),
-             Choice(MockScript('4', '4.mp3'), False),
-             Choice(MockScript('5', '5.mp3'), True)])
-        self.assertEqual('Selection largest number', q.question)
-        self.assertFalse(q[0].correct)
-        self.assertTrue(q[4].correct)
-
-    def test_choice_title_without_date(self):
-        script = MockScript('Title without date.', 'http://somewhere/')
-        choice = Choice(script, False)
-        self.assertEqual(str(choice), 'Title without date.')
-
-    def test_choice_title_strip_off_date_part(self):
-        script = MockScript('2008-09-17: KFC keeps recipe secret', 'http://somewhere/')
-        choice = Choice(script, False)
-        self.assertEqual(str(choice), 'KFC keeps recipe secret')
-
-
-class MockScript:
-    def __init__(self, title, mp3url):
-        self.title = title
-        self.mp3url = mp3url
-
-class QuizFromScriptsTest(unittest.TestCase):
-    def setUp(self):
-        self.scripts = [
-            MockScript('2008-01-02', 'http://localhost/1.mp3'),
-            MockScript('2008-02-03', 'http://localhost/2.mp3'),
-            MockScript('2008-03-04', 'http://localhost/3.mp3'),]
-        self.q = ChoiceQuiz.from_scripts(self.scripts)
-
-    def test_from_scripts(self):
-        self.assertEqual(len(self.scripts), len(self.q))
-
-    def test_shuffle(self):
-        self.q.shuffle()
-
-
-if __name__ == '__main__':
-    unittest.main()