aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/app_engine_server
diff options
context:
space:
mode:
authorDan Bornstein <danfuzz@android.com>2009-04-23 09:20:34 -0700
committerDan Bornstein <danfuzz@android.com>2009-04-23 09:20:34 -0700
commit9812825c46762b57846bdcadeb3b12b107998aae (patch)
tree65728948e2c82922ec7af42a917abbaf62fa1395 /scripts/app_engine_server
parent5e50c33e4893e8cebbe8a2aba68e27c87a9bc3ac (diff)
downloadsdk-9812825c46762b57846bdcadeb3b12b107998aae.zip
sdk-9812825c46762b57846bdcadeb3b12b107998aae.tar.gz
sdk-9812825c46762b57846bdcadeb3b12b107998aae.tar.bz2
Removed a superfluous backup file.
Diffstat (limited to 'scripts/app_engine_server')
-rwxr-xr-xscripts/app_engine_server/gae_shell/shell.py~308
1 files changed, 0 insertions, 308 deletions
diff --git a/scripts/app_engine_server/gae_shell/shell.py~ b/scripts/app_engine_server/gae_shell/shell.py~
deleted file mode 100755
index dee9fdb..0000000
--- a/scripts/app_engine_server/gae_shell/shell.py~
+++ /dev/null
@@ -1,308 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2007 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.
-
-"""
-An interactive, stateful AJAX shell that runs Python code on the server.
-
-Part of http://code.google.com/p/google-app-engine-samples/.
-
-May be run as a standalone app or in an existing app as an admin-only handler.
-Can be used for system administration tasks, as an interactive way to try out
-APIs, or as a debugging aid during development.
-
-The logging, os, sys, db, and users modules are imported automatically.
-
-Interpreter state is stored in the datastore so that variables, function
-definitions, and other values in the global and local namespaces can be used
-across commands.
-
-To use the shell in your app, copy shell.py, static/*, and templates/* into
-your app's source directory. Then, copy the URL handlers from app.yaml into
-your app.yaml.
-
-TODO: unit tests!
-"""
-
-import logging
-import new
-import os
-import pickle
-import sys
-import traceback
-import types
-import wsgiref.handlers
-
-from google.appengine.api import users
-from google.appengine.ext import db
-from google.appengine.ext import webapp
-from google.appengine.ext.webapp import template
-
-
-# Set to True if stack traces should be shown in the browser, etc.
-_DEBUG = True
-
-# The entity kind for shell sessions. Feel free to rename to suit your app.
-_SESSION_KIND = '_Shell_Session'
-
-# Types that can't be pickled.
-UNPICKLABLE_TYPES = (
- types.ModuleType,
- types.TypeType,
- types.ClassType,
- types.FunctionType,
- )
-
-# Unpicklable statements to seed new sessions with.
-INITIAL_UNPICKLABLES = [
- 'import logging',
- 'import os',
- 'import sys',
- 'from google.appengine.ext import db',
- 'from google.appengine.api import users',
- ]
-
-
-class Session(db.Model):
- """A shell session. Stores the session's globals.
-
- Each session globals is stored in one of two places:
-
- If the global is picklable, it's stored in the parallel globals and
- global_names list properties. (They're parallel lists to work around the
- unfortunate fact that the datastore can't store dictionaries natively.)
-
- If the global is not picklable (e.g. modules, classes, and functions), or if
- it was created by the same statement that created an unpicklable global,
- it's not stored directly. Instead, the statement is stored in the
- unpicklables list property. On each request, before executing the current
- statement, the unpicklable statements are evaluated to recreate the
- unpicklable globals.
-
- The unpicklable_names property stores all of the names of globals that were
- added by unpicklable statements. When we pickle and store the globals after
- executing a statement, we skip the ones in unpicklable_names.
-
- Using Text instead of string is an optimization. We don't query on any of
- these properties, so they don't need to be indexed.
- """
- global_names = db.ListProperty(db.Text)
- globals = db.ListProperty(db.Blob)
- unpicklable_names = db.ListProperty(db.Text)
- unpicklables = db.ListProperty(db.Text)
-
- def set_global(self, name, value):
- """Adds a global, or updates it if it already exists.
-
- Also removes the global from the list of unpicklable names.
-
- Args:
- name: the name of the global to remove
- value: any picklable value
- """
- blob = db.Blob(pickle.dumps(value))
-
- if name in self.global_names:
- index = self.global_names.index(name)
- self.globals[index] = blob
- else:
- self.global_names.append(db.Text(name))
- self.globals.append(blob)
-
- self.remove_unpicklable_name(name)
-
- def remove_global(self, name):
- """Removes a global, if it exists.
-
- Args:
- name: string, the name of the global to remove
- """
- if name in self.global_names:
- index = self.global_names.index(name)
- del self.global_names[index]
- del self.globals[index]
-
- def globals_dict(self):
- """Returns a dictionary view of the globals.
- """
- return dict((name, pickle.loads(val))
- for name, val in zip(self.global_names, self.globals))
-
- def add_unpicklable(self, statement, names):
- """Adds a statement and list of names to the unpicklables.
-
- Also removes the names from the globals.
-
- Args:
- statement: string, the statement that created new unpicklable global(s).
- names: list of strings; the names of the globals created by the statement.
- """
- self.unpicklables.append(db.Text(statement))
-
- for name in names:
- self.remove_global(name)
- if name not in self.unpicklable_names:
- self.unpicklable_names.append(db.Text(name))
-
- def remove_unpicklable_name(self, name):
- """Removes a name from the list of unpicklable names, if it exists.
-
- Args:
- name: string, the name of the unpicklable global to remove
- """
- if name in self.unpicklable_names:
- self.unpicklable_names.remove(name)
-
-
-class FrontPageHandler(webapp.RequestHandler):
- """Creates a new session and renders the shell.html template.
- """
-
- def get(self):
- # set up the session. TODO: garbage collect old shell sessions
- session_key = self.request.get('session')
- if session_key:
- session = Session.get(session_key)
- else:
- # create a new session
- session = Session()
- session.unpicklables = [db.Text(line) for line in INITIAL_UNPICKLABLES]
- session_key = session.put()
-
- template_file = os.path.join(os.path.dirname(__file__), 'templates',
- 'shell.html')
- session_url = '/?session=%s' % session_key
- vars = { 'server_software': os.environ['SERVER_SOFTWARE'],
- 'python_version': sys.version,
- 'session': str(session_key),
- 'user': users.get_current_user(),
- 'login_url': users.create_login_url(session_url),
- 'logout_url': users.create_logout_url(session_url),
- }
- rendered = webapp.template.render(template_file, vars, debug=_DEBUG)
- self.response.out.write(rendered)
-
-
-class StatementHandler(webapp.RequestHandler):
- """Evaluates a python statement in a given session and returns the result.
- """
-
- def get(self):
- self.response.headers['Content-Type'] = 'text/plain'
-
- # extract the statement to be run
- statement = self.request.get('statement')
- if not statement:
- return
-
- # the python compiler doesn't like network line endings
- statement = statement.replace('\r\n', '\n')
-
- # add a couple newlines at the end of the statement. this makes
- # single-line expressions such as 'class Foo: pass' evaluate happily.
- statement += '\n\n'
-
- # log and compile the statement up front
- try:
- logging.info('Compiling and evaluating:\n%s' % statement)
- compiled = compile(statement, '<string>', 'single')
- except:
- self.response.out.write(traceback.format_exc())
- return
-
- # create a dedicated module to be used as this statement's __main__
- statement_module = new.module('__main__')
-
- # use this request's __builtin__, since it changes on each request.
- # this is needed for import statements, among other things.
- import __builtin__
- statement_module.__builtins__ = __builtin__
-
- # load the session from the datastore
- session = Session.get(self.request.get('session'))
-
- # swap in our custom module for __main__. then unpickle the session
- # globals, run the statement, and re-pickle the session globals, all
- # inside it.
- old_main = sys.modules.get('__main__')
- try:
- sys.modules['__main__'] = statement_module
- statement_module.__name__ = '__main__'
-
- # re-evaluate the unpicklables
- for code in session.unpicklables:
- exec code in statement_module.__dict__
-
- # re-initialize the globals
- for name, val in session.globals_dict().items():
- try:
- statement_module.__dict__[name] = val
- except:
- msg = 'Dropping %s since it could not be unpickled.\n' % name
- self.response.out.write(msg)
- logging.warning(msg + traceback.format_exc())
- session.remove_global(name)
-
- # run!
- old_globals = dict(statement_module.__dict__)
- try:
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- try:
- sys.stdout = self.response.out
- sys.stderr = self.response.out
- exec compiled in statement_module.__dict__
- finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
- except:
- self.response.out.write(traceback.format_exc())
- return
-
- # extract the new globals that this statement added
- new_globals = {}
- for name, val in statement_module.__dict__.items():
- if name not in old_globals or val != old_globals[name]:
- new_globals[name] = val
-
- if True in [isinstance(val, UNPICKLABLE_TYPES)
- for val in new_globals.values()]:
- # this statement added an unpicklable global. store the statement and
- # the names of all of the globals it added in the unpicklables.
- session.add_unpicklable(statement, new_globals.keys())
- logging.debug('Storing this statement as an unpicklable.')
-
- else:
- # this statement didn't add any unpicklables. pickle and store the
- # new globals back into the datastore.
- for name, val in new_globals.items():
- if not name.startswith('__'):
- session.set_global(name, val)
-
- finally:
- sys.modules['__main__'] = old_main
-
- session.put()
-
-
-def main():
- application = webapp.WSGIApplication(
- [('/', FrontPageHandler),
- ('/shell.do', StatementHandler)], debug=_DEBUG)
- wsgiref.handlers.CGIHandler().run(application)
-
-
-if __name__ == '__main__':
- main()