Commits

Waldemar Kornewald  committed dcbecc9

initial import

  • Participants

Comments (0)

Files changed (19)

+syntax: glob
+.project
+.pydevproject
+.settings
+*~
+*.orig
+*.pyc
+*.pyo
+*.swp
+*.tmp
+desktop.ini
+nbproject

File __init__.py

Empty file added.
+# -*- coding: utf-8 -*-
+import logging, os, sys
+
+COMMON_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+PROJECT_DIR = os.path.dirname(COMMON_DIR)
+ZIP_PACKAGES_DIRS = (os.path.join(PROJECT_DIR, 'zip-packages'),
+                     os.path.join(COMMON_DIR, 'zip-packages'))
+# Overrides for os.environ
+env_ext = {'DJANGO_SETTINGS_MODULE': 'settings'}
+
+def setup_env():
+    """Configures app engine environment for command-line apps."""
+    # Try to import the appengine code from the system path.
+    try:
+        from google.appengine.api import apiproxy_stub_map
+    except ImportError:
+        for k in [k for k in sys.modules if k.startswith('google')]:
+            del sys.modules[k]
+
+        # Not on the system path. Build a list of alternative paths where it
+        # may be. First look within the project for a local copy, then look for
+        # where the Mac OS SDK installs it.
+        paths = [os.path.join(COMMON_DIR, '.google_appengine'),
+                 '/usr/local/google_appengine',
+                 '/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine']
+        for path in os.environ.get('PATH', '').replace(';', ':').split(':'):
+            path = path.rstrip(os.sep)
+            if path.endswith('google_appengine'):
+                paths.append(path)
+        if os.name in ('nt', 'dos'):
+            prefix = '%(PROGRAMFILES)s' % os.environ
+            paths.append(prefix + r'\Google\google_appengine')
+        # Loop through all possible paths and look for the SDK dir.
+        SDK_PATH = None
+        for sdk_path in paths:
+            sdk_path = os.path.realpath(sdk_path)
+            if os.path.exists(sdk_path):
+                SDK_PATH = sdk_path
+                break
+        if SDK_PATH is None:
+            # The SDK could not be found in any known location.
+            sys.stderr.write('The Google App Engine SDK could not be found!\n'
+                             'Visit http://code.google.com/p/app-engine-patch/'
+                             ' for installation instructions.\n')
+            sys.exit(1)
+        # Add the SDK and the libraries within it to the system path.
+        EXTRA_PATHS = [SDK_PATH]
+        lib = os.path.join(SDK_PATH, 'lib')
+        # Automatically add all packages in the SDK's lib folder:
+        for dir in os.listdir(lib):
+            path = os.path.join(lib, dir)
+            # Package can be under 'lib/<pkg>/<pkg>/' or 'lib/<pkg>/lib/<pkg>/'
+            detect = (os.path.join(path, dir), os.path.join(path, 'lib', dir))
+            for path in detect:
+                if os.path.isdir(path) and not dir == 'django':
+                    EXTRA_PATHS.append(os.path.dirname(path))
+                    break
+        sys.path = EXTRA_PATHS + sys.path
+        from google.appengine.api import apiproxy_stub_map
+
+    # Add this folder to sys.path
+    sys.path = [os.path.abspath(os.path.dirname(__file__))] + sys.path
+
+    setup_project()
+    setup_logging()
+
+def setup_threading():
+    # XXX: GAE's threading.local doesn't work correctly with subclassing
+    try:
+        from django.utils._threading_local import local
+        import threading
+        threading.local = local
+    except ImportError:
+        pass
+
+def setup_logging():
+    # Fix Python 2.6 logging module
+    logging.logMultiprocessing = 0
+
+    # Enable logging
+    from django.conf import settings
+    if settings.DEBUG:
+        logging.getLogger().setLevel(logging.DEBUG)
+    else:
+        logging.getLogger().setLevel(logging.INFO)
+
+def setup_project():
+    from .utils import on_production_server
+    if on_production_server:
+        # This fixes a pwd import bug for os.path.expanduser()
+        global env_ext
+        env_ext['HOME'] = PROJECT_DIR
+
+    os.environ.update(env_ext)
+
+    # Add the two parent folders and appenginepatcher's lib folder to sys.path.
+    # The current folder has to be added in main.py or setup_env(). This
+    # suggests a folder structure where you separate reusable code from project
+    # code:
+    # project -> common -> appenginepatch
+    # You can put a custom Django version into the "common" folder, for example.
+    EXTRA_PATHS = [
+        PROJECT_DIR,
+        COMMON_DIR,
+        os.path.dirname(PROJECT_DIR),
+    ]
+
+    EXTRA_PATHS.append(os.path.join(os.path.abspath(os.path.dirname(__file__)),
+        'lib'))
+
+    # We support zipped packages in the common and project folders.
+    # The files must be in the packages folder.
+    for packages_dir in ZIP_PACKAGES_DIRS:
+        if os.path.isdir(packages_dir):
+            for zip_package in os.listdir(packages_dir):
+                EXTRA_PATHS.append(os.path.join(packages_dir, zip_package))
+
+    # App Engine causes main.py to be reloaded if an exception gets raised
+    # on the first request of a main.py instance, so don't call setup_project()
+    # multiple times. We ensure this indirectly by checking if we've already
+    # modified sys.path.
+    if len(sys.path) < len(EXTRA_PATHS) or \
+            sys.path[:len(EXTRA_PATHS)] != EXTRA_PATHS:
+
+        sys.path = EXTRA_PATHS + sys.path

File db/__init__.py

+"""Appengine database backend."""
+
+
+"""
+App Engine backend for Django.
+"""
+
+from .creation import DatabaseCreation
+from ..utils import appid, have_appserver, on_production_server
+from django.db.backends import BaseDatabaseFeatures, BaseDatabaseOperations, \
+    BaseDatabaseWrapper, BaseDatabaseClient, BaseDatabaseValidation, BaseDatabaseIntrospection
+from google.appengine.ext.db import Error as GAEError
+import logging, os
+
+DatabaseError = GAEError
+IntegrityError = GAEError
+
+def auth_func():
+    import getpass
+    return raw_input('Login via Google Account:'), getpass.getpass('Password:')
+
+def rpc_server_factory(*args, ** kwargs):
+    from google.appengine.tools import appengine_rpc
+    kwargs['save_cookies'] = True
+    return appengine_rpc.HttpRpcServer(*args, ** kwargs)
+
+def get_datastore_paths(settings_dict):
+    """Returns a tuple with the path to the datastore and history file.
+
+    The datastore is stored in the same location as dev_appserver uses by
+    default, but the name is altered to be unique to this project so multiple
+    Django projects can be developed on the same machine in parallel.
+
+    Returns:
+      (datastore_path, history_path)
+    """
+    from google.appengine.tools import dev_appserver_main
+    options = settings_dict['OPTIONS']
+    datastore_path = options.get('datastore_path',
+                                 dev_appserver_main.DEFAULT_ARGS['datastore_path'].replace(
+                                 'dev_appserver', 'django_%s' % appid))
+    history_path = options.get('history_path',
+                               dev_appserver_main.DEFAULT_ARGS['history_path'].replace(
+                               'dev_appserver', 'django_%s' % appid))
+    return datastore_path, history_path
+
+def get_test_datastore_paths(inmemory=True):
+    """Returns a tuple with the path to the test datastore and history file.
+
+    If inmemory is true, (None, None) is returned to request an in-memory
+    datastore. If inmemory is false the path returned will be similar to the path
+    returned by get_datastore_paths but with a different name.
+
+    Returns:
+      (datastore_path, history_path)
+    """
+    if inmemory:
+        return None, None
+    datastore_path, history_path = get_datastore_paths()
+    datastore_path = datastore_path.replace('.datastore', '.testdatastore')
+    history_path = history_path.replace('.datastore', '.testdatastore')
+    return datastore_path, history_path
+
+def destroy_datastore(datastore_path, history_path):
+    """Destroys the appengine datastore at the specified paths."""
+    for path in (datastore_path, history_path):
+        if not path:
+            continue
+        try:
+            os.remove(path)
+        except OSError, error:
+            if error.errno != 2:
+                logging.error("Failed to clear datastore: %s" % error)
+
+class DatabaseFeatures(BaseDatabaseFeatures):
+    pass
+
+class DatabaseOperations(BaseDatabaseOperations):
+    def quote_name(self, name):
+        return name
+
+    def value_to_db_date(self, value):
+        # value is a date here, no need to check it
+        return value
+
+    def value_to_db_datetime(self, value):
+        # value is a datetime here, no need to check it
+        return value
+
+    def value_to_db_time(self, value):
+        # value is a time here, no need to check it
+        return value
+
+#    def value_to_db_decimal(self, value, max_digits, decimal_places):
+#        return 
+
+class DatabaseClient(BaseDatabaseClient):
+    pass
+
+class DatabaseValidation(BaseDatabaseValidation):
+    pass
+
+class DatabaseIntrospection(BaseDatabaseIntrospection):
+    def table_names(self):
+        "Returns a list of names of all tables that exist in the database."
+        return self.django_table_names(only_existing=False)
+
+class FakeCursor(object):
+    def __getattribute__(self, name):
+        raise TypeError("The App Engine backend doesn't support cursors.")
+
+    def __setattr__(self, name, value):
+        raise TypeError("The App Engine backend doesn't support cursors.")
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+    def __init__(self, * args, ** kwds):
+        super(DatabaseWrapper, self).__init__(*args, ** kwds)
+        self.features = DatabaseFeatures()
+        self.ops = DatabaseOperations()
+        self.client = DatabaseClient(self)
+        self.creation = DatabaseCreation(self)
+        self.validation = DatabaseValidation(self)
+        self.introspection = DatabaseIntrospection(self)
+        options = self.settings_dict['OPTIONS']
+        self.use_test_datastore = options.get('use_test_datastore', False)
+        self.test_datastore_inmemory = options.get('test_datastore_inmemory', True)
+        self.use_remote = options.get('use_remote', False)
+        if on_production_server:
+            self.use_remote = False
+        self.remote_app_id = options.get('remote_id', appid)
+        self.remote_host = options.get('remote_host', '%s.appspot.com' % self.remote_app_id)
+        self.remote_url = options.get('remote_url', '/remote_api')
+        self._setup_stubs()
+
+    def _get_paths(self):
+        if self.use_test_datastore:
+            return get_test_datastore_paths(self.test_datastore_inmemory)
+        else:
+            return get_datastore_paths(self.settings_dict)
+
+    def _setup_stubs(self):
+        # If this code is being run without an appserver (eg. via a django
+        # commandline flag) then setup a default stub environment.
+        if not have_appserver:
+            from google.appengine.tools import dev_appserver_main
+            args = dev_appserver_main.DEFAULT_ARGS.copy()
+            args['datastore_path'], args['history_path'] = self._get_paths()
+            from google.appengine.tools import dev_appserver
+            dev_appserver.SetupStubs(appid, ** args)
+        # If we're supposed to set up the remote_api, do that now.
+        if not self.use_test_datastore: # Never when testing
+            if self.use_remote:
+                self.setup_remote()
+
+    def setup_remote(self):
+        self.use_remote = True
+        logging.info('Setting up remote_api for "%s" at http://%s%s' %
+                     (self.remote_app_id, self.remote_host, self.remote_url)
+                     )
+        from google.appengine.ext.remote_api import remote_api_stub
+        from google.appengine.ext import db
+        remote_api_stub.ConfigureRemoteDatastore(self.remote_app_id,
+            self.remote_url, auth_func, self.remote_host,
+            rpc_server_factory=rpc_server_factory)
+        logging.info('Now using the datastore at "%s" at http://%s%s' %
+                     (self.remote_app_id, self.remote_host, self.remote_url))
+
+    def flush(self):
+        """Helper function to remove the current datastore and re-open the stubs"""
+        if self.use_remote:
+            import random, string
+            code = ''.join([random.choice(string.ascii_letters) for x in range(4)])
+            print '\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
+            print '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
+            print "Warning! You're about to delete the *production* datastore!"
+            print 'Only models defined in your INSTALLED_APPS can be removed!'
+            print 'If you want to clear the whole datastore you have to use the ' \
+                  'datastore viewer in the dashboard. Also, in order to delete all '\
+                  'unneeded indexes you have to run appcfg.py vacuum_indexes.'
+            print 'In order to proceed you have to enter the following code:'
+            print code
+            response = raw_input('Repeat: ')
+            if code == response:
+                print 'Deleting...'
+                from django.db import models
+                from google.appengine.api import datastore as ds
+                for model in models.get_models():
+                    print 'Deleting %s...' % model.kind()
+                    while True:
+                        data = ds.Query(model.kind(), keys_only=True).Get(200)
+                        if not data:
+                            break
+                        ds.Delete(data)
+                print "Datastore flushed! Please check your dashboard's " \
+                      'datastore viewer for any remaining entities and remove ' \
+                      'all unneeded indexes with manage.py vacuum_indexes.'
+            else:
+                print 'Aborting'
+                exit()
+        else:
+            destroy_datastore(*self._get_paths())
+        self._setup_stubs()
+
+    def _cursor(self):
+        return FakeCursor()

File db/creation.py

+from django.db.backends.creation import BaseDatabaseCreation
+
+class DatabaseCreation(BaseDatabaseCreation):
+    # This dictionary maps Field objects to their associated GAE column
+    # types, as strings. Column-type strings can contain format strings; they'll
+    # be interpolated against the values of Field.__dict__ before being output.
+    # If a column type is set to None, it won't be included in the output.
+    data_types = {
+        'DateTimeField':     'datetime',
+        'DateField':         'date',
+        'TimeField':         'time',
+        'FloatField':        'float',
+        'EmailField':        'email',
+        'URLField':          'link',
+        'BooleanField':      'bool',
+        'NullBooleanField':  'bool',
+        'CharField':         'text',
+        'CommaSeparatedIntegerField': 'text',
+        'IPAddressField':    'text',
+        'SlugField':         'text',
+        'FileField':         'text',
+        'FilePathField':     'text',
+        'TextField':         'longtext',
+        'XMLField':          'longtext',
+        'IntegerField':      'integer',
+        'SmallIntegerField': 'integer',
+        'PositiveIntegerField': 'integer',
+        'PositiveSmallIntegerField': 'integer',
+        'AutoField':         'integer',
+        'OneToOneField':     'integer',
+        'DecimalField':      'decimal',
+#        'ImageField':
+        # TODO: Add KeyField and a correspoding db_type
+    }
+
+    def create_test_db(self, *args, **kw):
+        """Destroys the test datastore. A new store will be recreated on demand"""
+        self.destroy_test_db()
+        self.connection.use_test_datastore = True
+        self.connection.flush()
+
+    def destroy_test_db(self, *args, **kw):
+        """Destroys the test datastore files."""
+        from .base import destroy_datastore, get_test_datastore_paths
+        destroy_datastore(*get_test_datastore_paths())

File lib/__init__.py

Empty file added.

File lib/memcache.py

+from google.appengine.api.memcache import *
+# -*- coding: utf-8 -*-
+import os, sys
+
+# Add parent folder to sys.path, so we can import aecmd.
+# App Engine causes main.py to be reloaded if an exception gets raised
+# on the first request of a main.py instance, so don't add parent_dir multiple
+# times.
+parent_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+if parent_dir not in sys.path:
+    sys.path = [parent_dir] + sys.path
+
+# Remove the standard version of Django
+for k in [k for k in sys.modules if k.startswith('django')]:
+    del sys.modules[k]
+
+from djangoappengine import aecmd
+aecmd.setup_threading()
+aecmd.setup_project()
+aecmd.setup_logging()
+
+import django.core.handlers.wsgi
+from google.appengine.ext.webapp import util
+from django.conf import settings
+
+def real_main():
+    # Reset path and environment variables
+    global path_backup
+    try:
+        sys.path = path_backup[:]
+    except:
+        path_backup = sys.path[:]
+    os.environ.update(aecmd.env_ext)
+    aecmd.setup_logging()
+
+    # Create a Django application for WSGI.
+    application = django.core.handlers.wsgi.WSGIHandler()
+
+    # Run the WSGI CGI handler with that application.
+    util.run_wsgi_app(application)
+
+def profile_main():
+    import logging, cProfile, pstats, random, StringIO
+    only_forced_profile = getattr(settings, 'ONLY_FORCED_PROFILE', False)
+    profile_percentage = getattr(settings, 'PROFILE_PERCENTAGE', None)
+    if (only_forced_profile and
+                'profile=forced' not in os.environ.get('QUERY_STRING')) or \
+            (not only_forced_profile and profile_percentage and
+                float(profile_percentage) / 100.0 <= random.random()):
+        return real_main()
+
+    prof = cProfile.Profile()
+    prof = prof.runctx('real_main()', globals(), locals())
+    stream = StringIO.StringIO()
+    stats = pstats.Stats(prof, stream=stream)
+    sort_by = getattr(settings, 'SORT_PROFILE_RESULTS_BY', 'time')
+    if not isinstance(sort_by, (list, tuple)):
+        sort_by = (sort_by,)
+    stats.sort_stats(*sort_by)
+
+    restrictions = []
+    profile_pattern = getattr(settings, 'PROFILE_PATTERN', None)
+    if profile_pattern:
+        restrictions.append(profile_pattern)
+    max_results = getattr(settings, 'MAX_PROFILE_RESULTS', 80)
+    if max_results and max_results != 'all':
+        restrictions.append(max_results)
+    stats.print_stats(*restrictions)
+    extra_output = getattr(settings, 'EXTRA_PROFILE_OUTPUT', None) or ()
+    if not isinstance(sort_by, (list, tuple)):
+        extra_output = (extra_output,)
+    if 'callees' in extra_output:
+        stats.print_callees()
+    if 'callers' in extra_output:
+        stats.print_callers()
+    logging.info('Profile data:\n%s', stream.getvalue())
+
+main = getattr(settings, 'ENABLE_PROFILER', False) and profile_main or real_main
+
+if __name__ == '__main__':
+    main()

File management/__init__.py

Empty file added.

File management/commands/__init__.py

Empty file added.

File management/commands/flush.py

+#!/usr/bin/python2.4
+#
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import os
+import sys
+
+from django.core.management.base import BaseCommand
+
+
+class Command(BaseCommand):
+    """Overrides the default Django flush command."""
+    help = 'Clears the current datastore and loads the initial fixture data.'
+
+    def run_from_argv(self, argv):
+        from django.db import connection
+        connection.flush()
+        from django.core.management import call_command
+        call_command('loaddata', 'initial_data')
+
+    def handle(self, *args, **kwargs):
+        self.run_from_argv(None)

File management/commands/runserver.py

+#!/usr/bin/python2.4
+#
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import os
+import sys
+import logging
+
+from django.db import connection
+
+from django.core.management.base import BaseCommand
+
+
+def start_dev_appserver(argv):
+  """Starts the appengine dev_appserver program for the Django project.
+
+  The appserver is run with default parameters. If you need to pass any special
+  parameters to the dev_appserver you will have to invoke it manually.
+  """
+  from google.appengine.tools import dev_appserver_main
+  progname = argv[0]
+  args = []
+  # hack __main__ so --help in dev_appserver_main works OK.
+  sys.modules['__main__'] = dev_appserver_main
+  # Set bind ip/port if specified.
+  addr, port = None, '8000'
+  if len(argv) > 2:
+    if not argv[2].startswith('-'):
+        addrport = argv[2]
+        try:
+          addr, port = addrport.split(":")
+        except ValueError:
+          addr, port = None, addrport
+        if not port.isdigit():
+          print "Error: '%s' is not a valid port number." % port
+          sys.exit(1)
+    else:
+      args.append(argv[2])
+    args.extend(argv[3:])
+  if addr:
+    args.extend(["--address", addr])
+  if port:
+    args.extend(["--port", port])
+  # Add email settings
+  from django.conf import settings
+  if '--smtp_host' not in args and '--enable_sendmail' not in args:
+    args.extend(['--smtp_host', settings.EMAIL_HOST,
+                 '--smtp_port', str(settings.EMAIL_PORT),
+                 '--smtp_user', settings.EMAIL_HOST_USER,
+                 '--smtp_password', settings.EMAIL_HOST_PASSWORD])
+  # Pass the application specific datastore location to the server.
+  p = connection._get_paths()
+  if '--datastore_path' not in args:
+    args.extend(["--datastore_path", p[0]])
+  if '--history_path' not in args:
+    args.extend(["--history_path", p[1]])
+
+  # Reset logging level to INFO as dev_appserver will spew tons of debug logs
+  logging.getLogger().setLevel(logging.INFO)
+
+  # Append the current working directory to the arguments.
+  dev_appserver_main.main([progname] + args + [os.getcwdu()])
+
+
+class Command(BaseCommand):
+    """Overrides the default Django runserver command.
+
+    Instead of starting the default Django development server this command
+    fires up a copy of the full fledged appengine dev_appserver that emulates
+    the live environment your application will be deployed to.
+    """
+    help = 'Runs a copy of the appengine development server.'
+    args = '[optional port number, or ipaddr:port]'
+
+    def run_from_argv(self, argv):
+      start_dev_appserver(argv)

File management/commands/testserver.py

+#!/usr/bin/python2.4
+#
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import os
+import sys
+
+from .runserver import start_dev_appserver
+from django.core.management.base import BaseCommand
+from djangoappengine.db.base import destroy_datastore, get_test_datastore_paths
+
+
+class Command(BaseCommand):
+    """Overrides the default Django testserver command.
+
+    Instead of starting the default Django development server this command fires
+    up a copy of the full fledged appengine dev_appserver.
+
+    The appserver is always initialised with a blank datastore with the specified
+    fixtures loaded into it.
+    """
+    help = 'Runs the development server with data from the given fixtures.'
+
+    def run_from_argv(self, argv):
+        fixtures = []
+        for arg in argv[2:]:
+            if arg.startswith('-'):
+                break
+            fixtures.append(arg)
+            argv.remove(arg)
+
+        try:
+            index = argv.index('--addrport')
+            addrport = argv[index + 1]
+            del argv[index:index+2]
+            argv = argv[:2] + [addrport] + argv[2:index] + argv[index+1:]
+        except:
+            pass
+
+        # Ensure an on-disk test datastore is used.
+        from django.db import connection
+        connection.use_test_datastore = True
+        connection.test_datastore_inmemory = False
+
+        # Flush any existing test datastore.
+        connection.flush()
+
+        # Load the fixtures.
+        from django.core.management import call_command
+        call_command('loaddata', 'initial_data')
+        if fixtures:
+            call_command('loaddata', *fixtures)
+
+        # Build new arguments for dev_appserver.
+        argv[1] = 'runserver'
+        datastore_path, history_path = get_test_datastore_paths(False)
+        argv.extend(['--datastore_path', datastore_path])
+        argv.extend(['--history_path', history_path])
+
+        start_dev_appserver(argv)

File management/commands/update.py

+#!/usr/bin/python2.4
+#
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# CHANGED: show warning if profiler is enabled, so you don't mistakenly upload
+# with non-production settings. Also, added --nosyncdb switch.
+
+import sys
+import logging
+
+from django.core.management.base import BaseCommand
+
+def run_appcfg(argv):
+    # import this so that we run through the checks at the beginning
+    # and report the appropriate errors
+    import appcfg
+
+    # We don't really want to use that one though, it just executes this one
+    from google.appengine.tools import appcfg
+
+    # Reset the logging level to WARN as appcfg will spew tons of logs on INFO
+    logging.getLogger().setLevel(logging.WARN)
+    
+    # Note: if we decide to change the name of this command to something other
+    # than 'update' we will have to munge the args to replace whatever
+    # we called it with 'update'
+    new_args = argv[:]
+    new_args.append('.')
+    syncdb = True
+    if '--nosyncdb' in new_args:
+        syncdb = False
+        new_args.remove('--nosyncdb')
+    appcfg.main(new_args)
+
+    if syncdb:
+        from django.core.management import call_command
+        from django.db import connection
+        connection.setup_remote()
+        print 'Running syncdb.'
+        call_command('syncdb', remote=True, interactive=True)
+
+    from django.conf import settings
+    if getattr(settings, 'ENABLE_PROFILER', False):
+        print '--------------------------\n' \
+              'WARNING: PROFILER ENABLED!\n' \
+              '--------------------------'
+
+class Command(BaseCommand):
+    """Calls the appcfg.py's update command for the current project.
+
+    Any additional arguments are passed directly to appcfg.py.
+    """
+    help = 'Calls appcfg.py update for the current project.'
+    args = '[any appcfg.py options]'
+
+    def run_from_argv(self, argv):
+        run_appcfg(argv)

File models.py

Empty file added.

File settings_post.py

+# -*- coding: utf-8 -*-
+from settings import *
+import sys
+
+if '%d' in MEDIA_URL:
+    MEDIA_URL = MEDIA_URL % MEDIA_VERSION
+if '%s' in ADMIN_MEDIA_PREFIX:
+    ADMIN_MEDIA_PREFIX = ADMIN_MEDIA_PREFIX % MEDIA_URL
+
+TEMPLATE_DEBUG = DEBUG
+MANAGERS = ADMINS
+
+# You can override Django's or some apps' locales with these folders:
+if os.path.exists(os.path.join(COMMON_DIR, 'locale_overrides_common')):
+    INSTALLED_APPS += ('locale_overrides_common',)
+if os.path.exists(os.path.join(PROJECT_DIR, 'locale_overrides')):
+    INSTALLED_APPS += ('locale_overrides',)
+
+## Add admin interface media files if necessary
+#if 'django.contrib.admin' in INSTALLED_APPS:
+#    INSTALLED_APPS += ('django_export.admin_media',)
+#
+## Always add Django templates (exported from zip)
+#INSTALLED_APPS += (
+#    'django_export.django_templates',
+#)
+
+if have_appserver or on_production_server:
+    check_app_imports = None
+else:
+    def check_app_imports(app):
+        before = sys.modules.keys()
+        __import__(app, {}, {}, [''])
+        after = sys.modules.keys()
+        added = [key[len(app)+1:] for key in after if key not in before and
+                 key.startswith(app + '.') and key[len(app)+1:]]
+        if added:
+            import logging
+            logging.warn('The app "%(app)s" contains imports in '
+                         'its __init__.py (at least %(added)s). This can cause '
+                         'strange bugs due to recursive imports! You should '
+                         'either do the import lazily (within functions) or '
+                         'ignore the app settings/urlsauto with '
+                         'IGNORE_APP_SETTINGS and IGNORE_APP_URLSAUTO in '
+                         'your settings.py.'
+                         % {'app': app, 'added': ', '.join(added)})
+
+# Import app-specific settings
+_globals = globals()
+class _Module(object):
+    def __setattr__(self, key, value):
+        _globals[key] = value
+    def __getattribute__(self, key):
+        return _globals[key]
+    def __hasattr__(self, key):
+        return key in _globals
+settings = _Module()
+
+for app in INSTALLED_APPS:
+    # This is an optimization. Django's apps don't have special settings.
+    # Also, allow for ignoring some apps' settings.
+    if app.startswith('django.') or app.endswith('.*') or \
+            app == 'djangoappengine' or app in IGNORE_APP_SETTINGS:
+        continue
+    try:
+        # First we check if __init__.py doesn't import anything
+        if check_app_imports:
+            check_app_imports(app)
+        __import__(app + '.settings', {}, {}, [''])
+    except ImportError:
+        pass
+
+try:
+    from settings_overrides import *
+except ImportError:
+    pass

File settings_pre.py

+# -*- coding: utf-8 -*-
+from djangoappengine.utils import on_production_server, have_appserver
+import os
+DEBUG = not on_production_server
+
+# The MEDIA_VERSION will get integrated via %d
+MEDIA_URL = '/media/'
+# The MEDIA_URL will get integrated via %s
+ADMIN_MEDIA_PREFIX = '%sadmin_media/'
+
+ADMINS = ()
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'djangoappengine.db',
+        'NAME': '',
+        'USER': '',
+        'PASSWORD': '',
+        'HOST': '',
+        'PORT': '',
+        'SUPPORTS_TRANSACTIONS': False,
+    },
+}
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+EMAIL_HOST = 'localhost'
+EMAIL_PORT = 25
+EMAIL_HOST_USER = 'user'
+EMAIL_HOST_PASSWORD = 'password'
+EMAIL_USE_TLS = True
+DEFAULT_FROM_EMAIL = 'user@localhost'
+SERVER_EMAIL = 'user@localhost'
+
+ROOT_URLCONF = 'urls'
+
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+)
+
+COMMON_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+PROJECT_DIR = os.path.dirname(COMMON_DIR)
+MAIN_DIRS = (PROJECT_DIR, COMMON_DIR)
+
+TEMPLATE_DIRS = tuple([os.path.join(dir, 'templates') for dir in MAIN_DIRS])
+
+LOCALE_PATHS = (
+    os.path.join(PROJECT_DIR, 'media', 'locale'),
+) + tuple([os.path.join(dir, 'locale') for dir in TEMPLATE_DIRS])
+
+FILE_UPLOAD_HANDLERS = (
+    'django.core.files.uploadhandler.MemoryFileUploadHandler',
+)
+
+CACHE_BACKEND = 'memcached://?timeout=0'
+SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
+
+if not on_production_server:
+    INTERNAL_IPS = ('127.0.0.1',)
+
+IGNORE_APP_SETTINGS = ()
+from google.appengine.api import apiproxy_stub_map
+import os
+
+have_appserver = bool(apiproxy_stub_map.apiproxy.GetStub('datastore_v3'))
+
+if have_appserver:
+    appid = os.environ.get('APPLICATION_ID')
+else:
+    try:
+        from google.appengine.tools import dev_appserver
+        from aecmd import PROJECT_DIR
+        appconfig, unused = dev_appserver.LoadAppConfig(PROJECT_DIR, {})
+        appid = appconfig.application
+    except ImportError:
+        appid = None
+
+on_production_server = have_appserver and \
+    not os.environ.get('SERVER_SOFTWARE', '').lower().startswith('devel')