author | Pawel Solyga <Pawel.Solyga@gmail.com> |
Sun, 24 May 2009 22:29:54 +0200 | |
changeset 2335 | 366e64ecba91 |
child 2344 | 621252e2cc18 |
permissions | -rw-r--r-- |
2335
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
1 |
#!/usr/bin/python |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
2 |
# |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
3 |
# Copyright 2007 Google Inc. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
4 |
# |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
5 |
# Licensed under the Apache License, Version 2.0 (the "License"); |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
6 |
# you may not use this file except in compliance with the License. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
7 |
# You may obtain a copy of the License at |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
8 |
# |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
9 |
# http://www.apache.org/licenses/LICENSE-2.0 |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
10 |
# |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
11 |
# Unless required by applicable law or agreed to in writing, software |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
12 |
# distributed under the License is distributed on an "AS IS" BASIS, |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
13 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
14 |
# See the License for the specific language governing permissions and |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
15 |
# limitations under the License. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
16 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
17 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
18 |
An interactive, stateful AJAX shell that runs Python code on the server. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
19 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
20 |
Part of http://code.google.com/p/google-app-engine-samples/. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
21 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
22 |
May be run as a standalone app or in an existing app as an admin-only handler. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
23 |
Can be used for system administration tasks, as an interactive way to try out |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
24 |
APIs, or as a debugging aid during development. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
25 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
26 |
The logging, os, sys, db, and users modules are imported automatically. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
27 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
28 |
Interpreter state is stored in the datastore so that variables, function |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
29 |
definitions, and other values in the global and local namespaces can be used |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
30 |
across commands. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
31 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
32 |
To use the shell in your app, copy shell.py, static/*, and templates/* into |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
33 |
your app's source directory. Then, copy the URL handlers from app.yaml into |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
34 |
your app.yaml. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
35 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
36 |
TODO: unit tests! |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
37 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
38 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
39 |
import logging |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
40 |
import new |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
41 |
import os |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
42 |
import pickle |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
43 |
import sys |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
44 |
import traceback |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
45 |
import types |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
46 |
import wsgiref.handlers |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
47 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
48 |
from django.template import loader |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
49 |
from google.appengine.api import users |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
50 |
from google.appengine.ext import db |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
51 |
from google.appengine.ext import webapp |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
52 |
from google.appengine.ext.webapp import template |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
53 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
54 |
import gae_django |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
55 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
56 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
57 |
# Set to True if stack traces should be shown in the browser, etc. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
58 |
_DEBUG = True |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
59 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
60 |
# The entity kind for shell sessions. Feel free to rename to suit your app. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
61 |
_SESSION_KIND = '_Shell_Session' |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
62 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
63 |
# Types that can't be pickled. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
64 |
UNPICKLABLE_TYPES = ( |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
65 |
types.ModuleType, |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
66 |
types.TypeType, |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
67 |
types.ClassType, |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
68 |
types.FunctionType, |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
69 |
) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
70 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
71 |
# Unpicklable statements to seed new sessions with. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
72 |
INITIAL_UNPICKLABLES = [ |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
73 |
'import logging', |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
74 |
'import os', |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
75 |
'import sys', |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
76 |
'from google.appengine.ext import db', |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
77 |
'from google.appengine.api import users', |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
78 |
] |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
79 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
80 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
81 |
class ShellSession(db.Model): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
82 |
"""A shell session. Stores the session's globals. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
83 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
84 |
Each session globals is stored in one of two places: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
85 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
86 |
If the global is picklable, it's stored in the parallel globals and |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
87 |
global_names list properties. (They're parallel lists to work around the |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
88 |
unfortunate fact that the datastore can't store dictionaries natively.) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
89 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
90 |
If the global is not picklable (e.g. modules, classes, and functions), or if |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
91 |
it was created by the same statement that created an unpicklable global, |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
92 |
it's not stored directly. Instead, the statement is stored in the |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
93 |
unpicklables list property. On each request, before executing the current |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
94 |
statement, the unpicklable statements are evaluated to recreate the |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
95 |
unpicklable globals. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
96 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
97 |
The unpicklable_names property stores all of the names of globals that were |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
98 |
added by unpicklable statements. When we pickle and store the globals after |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
99 |
executing a statement, we skip the ones in unpicklable_names. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
100 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
101 |
Using Text instead of string is an optimization. We don't query on any of |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
102 |
these properties, so they don't need to be indexed. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
103 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
104 |
global_names = db.ListProperty(db.Text) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
105 |
globals = db.ListProperty(db.Blob) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
106 |
unpicklable_names = db.ListProperty(db.Text) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
107 |
unpicklables = db.ListProperty(db.Text) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
108 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
109 |
def set_global(self, name, value): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
110 |
"""Adds a global, or updates it if it already exists. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
111 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
112 |
Also removes the global from the list of unpicklable names. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
113 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
114 |
Args: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
115 |
name: the name of the global to remove |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
116 |
value: any picklable value |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
117 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
118 |
blob = db.Blob(pickle.dumps(value)) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
119 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
120 |
if name in self.global_names: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
121 |
index = self.global_names.index(name) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
122 |
self.globals[index] = blob |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
123 |
else: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
124 |
self.global_names.append(db.Text(name)) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
125 |
self.globals.append(blob) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
126 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
127 |
self.remove_unpicklable_name(name) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
128 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
129 |
def remove_global(self, name): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
130 |
"""Removes a global, if it exists. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
131 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
132 |
Args: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
133 |
name: string, the name of the global to remove |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
134 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
135 |
if name in self.global_names: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
136 |
index = self.global_names.index(name) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
137 |
del self.global_names[index] |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
138 |
del self.globals[index] |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
139 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
140 |
def globals_dict(self): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
141 |
"""Returns a dictionary view of the globals. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
142 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
143 |
return dict((name, pickle.loads(val)) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
144 |
for name, val in zip(self.global_names, self.globals)) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
145 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
146 |
def add_unpicklable(self, statement, names): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
147 |
"""Adds a statement and list of names to the unpicklables. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
148 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
149 |
Also removes the names from the globals. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
150 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
151 |
Args: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
152 |
statement: string, the statement that created new unpicklable global(s). |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
153 |
names: list of strings; the names of the globals created by the statement. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
154 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
155 |
self.unpicklables.append(db.Text(statement)) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
156 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
157 |
for name in names: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
158 |
self.remove_global(name) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
159 |
if name not in self.unpicklable_names: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
160 |
self.unpicklable_names.append(db.Text(name)) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
161 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
162 |
def remove_unpicklable_name(self, name): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
163 |
"""Removes a name from the list of unpicklable names, if it exists. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
164 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
165 |
Args: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
166 |
name: string, the name of the unpicklable global to remove |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
167 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
168 |
if name in self.unpicklable_names: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
169 |
self.unpicklable_names.remove(name) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
170 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
171 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
172 |
class FrontPageHandler(webapp.RequestHandler): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
173 |
"""Creates a new session and renders the shell.html template. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
174 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
175 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
176 |
def get(self): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
177 |
# set up the session. TODO: garbage collect old shell sessions |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
178 |
session_key = self.request.get('session') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
179 |
if session_key: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
180 |
session = ShellSession.get(session_key) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
181 |
else: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
182 |
# create a new session |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
183 |
session = ShellSession() |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
184 |
session.unpicklables = [db.Text(line) for line in INITIAL_UNPICKLABLES] |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
185 |
session_key = session.put() |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
186 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
187 |
template_file = os.path.join(os.path.dirname(__file__), 'templates', |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
188 |
'shell.html') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
189 |
session_url = '/?session=%s' % session_key |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
190 |
vars = { 'server_software': os.environ['SERVER_SOFTWARE'], |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
191 |
'python_version': sys.version, |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
192 |
'session': str(session_key), |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
193 |
'user': users.get_current_user(), |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
194 |
'login_url': users.create_login_url(session_url), |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
195 |
'logout_url': users.create_logout_url(session_url), |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
196 |
} |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
197 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
198 |
rendered = loader.render_to_string('shell.html', dictionary=vars) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
199 |
# rendered = webapp.template.render(template_file, vars, debug=_DEBUG) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
200 |
self.response.out.write(rendered) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
201 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
202 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
203 |
class StatementHandler(webapp.RequestHandler): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
204 |
"""Evaluates a python statement in a given session and returns the result. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
205 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
206 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
207 |
def get(self): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
208 |
self.response.headers['Content-Type'] = 'text/plain' |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
209 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
210 |
# extract the statement to be run |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
211 |
statement = self.request.get('statement') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
212 |
if not statement: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
213 |
return |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
214 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
215 |
# the python compiler doesn't like network line endings |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
216 |
statement = statement.replace('\r\n', '\n') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
217 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
218 |
# add a couple newlines at the end of the statement. this makes |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
219 |
# single-line expressions such as 'class Foo: pass' evaluate happily. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
220 |
statement += '\n\n' |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
221 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
222 |
# log and compile the statement up front |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
223 |
try: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
224 |
logging.info('Compiling and evaluating:\n%s' % statement) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
225 |
compiled = compile(statement, '<string>', 'single') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
226 |
except: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
227 |
self.response.out.write(traceback.format_exc()) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
228 |
return |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
229 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
230 |
# create a dedicated module to be used as this statement's __main__ |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
231 |
statement_module = new.module('__main__') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
232 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
233 |
# use this request's __builtin__, since it changes on each request. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
234 |
# this is needed for import statements, among other things. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
235 |
import __builtin__ |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
236 |
statement_module.__builtins__ = __builtin__ |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
237 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
238 |
# load the session from the datastore |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
239 |
session = ShellSession.get(self.request.get('session')) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
240 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
241 |
# swap in our custom module for __main__. then unpickle the session |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
242 |
# globals, run the statement, and re-pickle the session globals, all |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
243 |
# inside it. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
244 |
old_main = sys.modules.get('__main__') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
245 |
try: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
246 |
sys.modules['__main__'] = statement_module |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
247 |
statement_module.__name__ = '__main__' |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
248 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
249 |
# re-evaluate the unpicklables |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
250 |
for code in session.unpicklables: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
251 |
exec code in statement_module.__dict__ |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
252 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
253 |
# re-initialize the globals |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
254 |
for name, val in session.globals_dict().items(): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
255 |
try: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
256 |
statement_module.__dict__[name] = val |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
257 |
except: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
258 |
msg = 'Dropping %s since it could not be unpickled.\n' % name |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
259 |
self.response.out.write(msg) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
260 |
logging.warning(msg + traceback.format_exc()) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
261 |
session.remove_global(name) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
262 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
263 |
# run! |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
264 |
old_globals = dict(statement_module.__dict__) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
265 |
try: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
266 |
old_stdout = sys.stdout |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
267 |
old_stderr = sys.stderr |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
268 |
try: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
269 |
sys.stdout = self.response.out |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
270 |
sys.stderr = self.response.out |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
271 |
exec compiled in statement_module.__dict__ |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
272 |
finally: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
273 |
sys.stdout = old_stdout |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
274 |
sys.stderr = old_stderr |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
275 |
except: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
276 |
self.response.out.write(traceback.format_exc()) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
277 |
return |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
278 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
279 |
# extract the new globals that this statement added |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
280 |
new_globals = {} |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
281 |
for name, val in statement_module.__dict__.items(): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
282 |
if name not in old_globals or val != old_globals[name]: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
283 |
new_globals[name] = val |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
284 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
285 |
if True in [isinstance(val, UNPICKLABLE_TYPES) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
286 |
for val in new_globals.values()]: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
287 |
# this statement added an unpicklable global. store the statement and |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
288 |
# the names of all of the globals it added in the unpicklables. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
289 |
session.add_unpicklable(statement, new_globals.keys()) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
290 |
logging.debug('Storing this statement as an unpicklable.') |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
291 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
292 |
else: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
293 |
# this statement didn't add any unpicklables. pickle and store the |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
294 |
# new globals back into the datastore. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
295 |
for name, val in new_globals.items(): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
296 |
if not name.startswith('__'): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
297 |
session.set_global(name, val) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
298 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
299 |
finally: |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
300 |
sys.modules['__main__'] = old_main |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
301 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
302 |
session.put() |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
303 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
304 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
305 |
def main(): |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
306 |
"""Main program. |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
307 |
""" |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
308 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
309 |
application = webapp.WSGIApplication( |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
310 |
[('/admin/shell', FrontPageHandler), |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
311 |
('/admin/shell/shell.do', StatementHandler)], debug=_DEBUG) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
312 |
wsgiref.handlers.CGIHandler().run(application) |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
313 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
314 |
|
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
315 |
if __name__ == '__main__': |
366e64ecba91
Add web based python shell to Melange.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff
changeset
|
316 |
main() |