serverdensity-heroku 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +4 -0
- data/Rakefile +1 -0
- data/bin/LICENSE +27 -0
- data/bin/LICENSE-minjson +504 -0
- data/bin/agent-heroku-test.py +2 -0
- data/bin/agent.py +503 -0
- data/bin/checks.py +2497 -0
- data/bin/checks.pyc +0 -0
- data/bin/config.cfg +56 -0
- data/bin/daemon.py +174 -0
- data/bin/daemon.pyc +0 -0
- data/bin/minjson.py +280 -0
- data/bin/plugins.py +315 -0
- data/bin/sd-agent-pkg.init +85 -0
- data/bin/sd-agent.init +73 -0
- data/bin/sd-deploy.py +317 -0
- data/lib/serverdensity-heroku/version.rb +5 -0
- data/lib/serverdensity-heroku.rb +10 -0
- data/serverdensity-heroku.gemspec +19 -0
- metadata +82 -0
data/bin/checks.pyc
ADDED
Binary file
|
data/bin/config.cfg
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#
|
2
|
+
# Server Density Agent Config
|
3
|
+
# Docs: http://support.serverdensity.com/knowledgebase/articles/69360-agent-config-variables-linux-mac-freebsd
|
4
|
+
#
|
5
|
+
|
6
|
+
[Main]
|
7
|
+
sd_url: http://robelkin.serverdensity.com
|
8
|
+
agent_key: be935d3c673f3611097bdb711a685d1b
|
9
|
+
|
10
|
+
#
|
11
|
+
# Plugins
|
12
|
+
#
|
13
|
+
# Leave blank to ignore. See http://support.serverdensity.com/knowledgebase/articles/76018-writing-a-plugin-linux-mac-and-freebsd
|
14
|
+
#
|
15
|
+
|
16
|
+
plugin_directory:
|
17
|
+
|
18
|
+
#
|
19
|
+
# Optional status monitoring
|
20
|
+
#
|
21
|
+
# See http://support.serverdensity.com/knowledgebase/topics/10921-configuration
|
22
|
+
# Ignore these if you do not wish to monitor them
|
23
|
+
#
|
24
|
+
|
25
|
+
# Apache
|
26
|
+
# See http://support.serverdensity.com/knowledgebase/articles/71145-apache-monitoring-linux-mac-and-freebsd
|
27
|
+
|
28
|
+
apache_status_url: http://www.example.com/server-status/?auto
|
29
|
+
apache_status_user:
|
30
|
+
apache_status_pass:
|
31
|
+
|
32
|
+
# MongoDB
|
33
|
+
# See http://support.serverdensity.com/knowledgebase/articles/71151-mongodb-monitoring-linux-mac-and-freebsd
|
34
|
+
|
35
|
+
mongodb_server:
|
36
|
+
mongodb_dbstats: no
|
37
|
+
mongodb_replset: no
|
38
|
+
|
39
|
+
# MySQL
|
40
|
+
# See http://support.serverdensity.com/knowledgebase/articles/71166-mysql-monitoring-linux-mac-and-freebsd
|
41
|
+
|
42
|
+
mysql_server:
|
43
|
+
mysql_user:
|
44
|
+
mysql_pass:
|
45
|
+
|
46
|
+
# nginx
|
47
|
+
# See http://support.serverdensity.com/knowledgebase/articles/75885-nginx-monitoring-linux-mac-and-freebsd
|
48
|
+
|
49
|
+
nginx_status_url: http://www.example.com/nginx_status
|
50
|
+
|
51
|
+
# RabbitMQ
|
52
|
+
# See http://support.serverdensity.com/knowledgebase/articles/75888-rabbitmq-monitoring-linux-mac-and-freebsd
|
53
|
+
|
54
|
+
rabbitmq_status_url: http://www.example.com:55672/json
|
55
|
+
rabbitmq_user: guest
|
56
|
+
rabbitmq_pass: guest
|
data/bin/daemon.py
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
'''
|
2
|
+
***
|
3
|
+
Modified generic daemon class
|
4
|
+
***
|
5
|
+
|
6
|
+
Author: http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
|
7
|
+
www.boxedice.com
|
8
|
+
|
9
|
+
License: http://creativecommons.org/licenses/by-sa/3.0/
|
10
|
+
|
11
|
+
Changes: 23rd Jan 2009 (David Mytton <david@boxedice.com>)
|
12
|
+
- Replaced hard coded '/dev/null in __init__ with os.devnull
|
13
|
+
- Added OS check to conditionally remove code that doesn't work on OS X
|
14
|
+
- Added output to console on completion
|
15
|
+
- Tidied up formatting
|
16
|
+
11th Mar 2009 (David Mytton <david@boxedice.com>)
|
17
|
+
- Fixed problem with daemon exiting on Python 2.4 (before SystemExit was part of the Exception base)
|
18
|
+
13th Aug 2010 (David Mytton <david@boxedice.com>
|
19
|
+
- Fixed unhandled exception if PID file is empty
|
20
|
+
'''
|
21
|
+
|
22
|
+
# Core modules
|
23
|
+
import atexit
|
24
|
+
import os
|
25
|
+
import sys
|
26
|
+
import time
|
27
|
+
|
28
|
+
from signal import SIGTERM
|
29
|
+
|
30
|
+
class Daemon:
|
31
|
+
"""
|
32
|
+
A generic daemon class.
|
33
|
+
|
34
|
+
Usage: subclass the Daemon class and override the run() method
|
35
|
+
"""
|
36
|
+
def __init__(self, pidfile, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull):
|
37
|
+
self.stdin = stdin
|
38
|
+
self.stdout = stdout
|
39
|
+
self.stderr = stderr
|
40
|
+
self.pidfile = pidfile
|
41
|
+
|
42
|
+
def daemonize(self):
|
43
|
+
"""
|
44
|
+
Do the UNIX double-fork magic, see Stevens' "Advanced
|
45
|
+
Programming in the UNIX Environment" for details (ISBN 0201563177)
|
46
|
+
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
47
|
+
"""
|
48
|
+
try:
|
49
|
+
pid = os.fork()
|
50
|
+
if pid > 0:
|
51
|
+
# Exit first parent
|
52
|
+
sys.exit(0)
|
53
|
+
except OSError, e:
|
54
|
+
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
|
55
|
+
sys.exit(1)
|
56
|
+
|
57
|
+
# Decouple from parent environment
|
58
|
+
os.chdir("/")
|
59
|
+
os.setsid()
|
60
|
+
os.umask(0)
|
61
|
+
|
62
|
+
# Do second fork
|
63
|
+
try:
|
64
|
+
pid = os.fork()
|
65
|
+
if pid > 0:
|
66
|
+
# Exit from second parent
|
67
|
+
sys.exit(0)
|
68
|
+
except OSError, e:
|
69
|
+
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
|
70
|
+
sys.exit(1)
|
71
|
+
|
72
|
+
if sys.platform != 'darwin': # This block breaks on OS X
|
73
|
+
# Redirect standard file descriptors
|
74
|
+
sys.stdout.flush()
|
75
|
+
sys.stderr.flush()
|
76
|
+
si = file(self.stdin, 'r')
|
77
|
+
so = file(self.stdout, 'a+')
|
78
|
+
se = file(self.stderr, 'a+', 0)
|
79
|
+
os.dup2(si.fileno(), sys.stdin.fileno())
|
80
|
+
os.dup2(so.fileno(), sys.stdout.fileno())
|
81
|
+
os.dup2(se.fileno(), sys.stderr.fileno())
|
82
|
+
|
83
|
+
print "Started"
|
84
|
+
|
85
|
+
# Write pidfile
|
86
|
+
atexit.register(self.delpid) # Make sure pid file is removed if we quit
|
87
|
+
pid = str(os.getpid())
|
88
|
+
file(self.pidfile,'w+').write("%s\n" % pid)
|
89
|
+
|
90
|
+
def delpid(self):
|
91
|
+
os.remove(self.pidfile)
|
92
|
+
|
93
|
+
def start(self):
|
94
|
+
"""
|
95
|
+
Start the daemon
|
96
|
+
"""
|
97
|
+
|
98
|
+
print "Starting..."
|
99
|
+
|
100
|
+
# Check for a pidfile to see if the daemon already runs
|
101
|
+
try:
|
102
|
+
pf = file(self.pidfile,'r')
|
103
|
+
pid = int(pf.read().strip())
|
104
|
+
pf.close()
|
105
|
+
except IOError:
|
106
|
+
pid = None
|
107
|
+
except SystemExit:
|
108
|
+
pid = None
|
109
|
+
|
110
|
+
if pid:
|
111
|
+
message = "pidfile %s already exists. Is it already running?\n"
|
112
|
+
sys.stderr.write(message % self.pidfile)
|
113
|
+
sys.exit(1)
|
114
|
+
|
115
|
+
# Start the daemon
|
116
|
+
self.daemonize()
|
117
|
+
self.run()
|
118
|
+
|
119
|
+
def stop(self):
|
120
|
+
"""
|
121
|
+
Stop the daemon
|
122
|
+
"""
|
123
|
+
|
124
|
+
print "Stopping..."
|
125
|
+
|
126
|
+
# Get the pid from the pidfile
|
127
|
+
try:
|
128
|
+
pf = file(self.pidfile,'r')
|
129
|
+
pid = int(pf.read().strip())
|
130
|
+
pf.close()
|
131
|
+
except IOError:
|
132
|
+
pid = None
|
133
|
+
except ValueError:
|
134
|
+
pid = None
|
135
|
+
|
136
|
+
if not pid:
|
137
|
+
message = "pidfile %s does not exist. Not running?\n"
|
138
|
+
sys.stderr.write(message % self.pidfile)
|
139
|
+
|
140
|
+
# Just to be sure. A ValueError might occur if the PID file is empty but does actually exist
|
141
|
+
if os.path.exists(self.pidfile):
|
142
|
+
os.remove(self.pidfile)
|
143
|
+
|
144
|
+
return # Not an error in a restart
|
145
|
+
|
146
|
+
# Try killing the daemon process
|
147
|
+
try:
|
148
|
+
while 1:
|
149
|
+
os.kill(pid, SIGTERM)
|
150
|
+
time.sleep(0.1)
|
151
|
+
except OSError, err:
|
152
|
+
err = str(err)
|
153
|
+
if err.find("No such process") > 0:
|
154
|
+
if os.path.exists(self.pidfile):
|
155
|
+
os.remove(self.pidfile)
|
156
|
+
else:
|
157
|
+
print str(err)
|
158
|
+
sys.exit(1)
|
159
|
+
|
160
|
+
print "Stopped"
|
161
|
+
|
162
|
+
def restart(self):
|
163
|
+
"""
|
164
|
+
Restart the daemon
|
165
|
+
"""
|
166
|
+
self.stop()
|
167
|
+
self.start()
|
168
|
+
|
169
|
+
def run(self):
|
170
|
+
"""
|
171
|
+
You should override this method when you subclass Daemon. It will be called after the process has been
|
172
|
+
daemonized by start() or restart().
|
173
|
+
"""
|
174
|
+
|
data/bin/daemon.pyc
ADDED
Binary file
|
data/bin/minjson.py
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
##############################################################################
|
2
|
+
##
|
3
|
+
## minjson.py implements JSON reading and writing in python.
|
4
|
+
## Copyright (c) 2005 Jim Washington and Contributors.
|
5
|
+
##
|
6
|
+
## This library is free software; you can redistribute it and/or
|
7
|
+
## modify it under the terms of the GNU Lesser General Public
|
8
|
+
## License as published by the Free Software Foundation; either
|
9
|
+
## version 2.1 of the License, or (at your option) any later version.
|
10
|
+
##
|
11
|
+
## This library is distributed in the hope that it will be useful,
|
12
|
+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
## Lesser General Public License for more details.=
|
15
|
+
##
|
16
|
+
## You should have received a copy of the GNU Lesser General Public
|
17
|
+
## License along with this library; if not, write to the Free Software
|
18
|
+
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
##
|
20
|
+
##############################################################################
|
21
|
+
|
22
|
+
|
23
|
+
# minjson.py
|
24
|
+
# use python's parser to read minimal javascript objects.
|
25
|
+
# str's objects and fixes the text to write javascript.
|
26
|
+
|
27
|
+
# Thanks to Patrick Logan for starting the json-py project and making so many
|
28
|
+
# good test cases.
|
29
|
+
|
30
|
+
# Jim Washington 7 Aug 2005.
|
31
|
+
|
32
|
+
from re import compile, sub, search, DOTALL
|
33
|
+
|
34
|
+
# set to true if transmission size is much more important than speed
|
35
|
+
# only affects writing, and makes a minimal difference in output size.
|
36
|
+
alwaysStripWhiteSpace = False
|
37
|
+
|
38
|
+
# add to this string if you wish to exclude additional math operators
|
39
|
+
# from reading.
|
40
|
+
badOperators = '*'
|
41
|
+
|
42
|
+
#################################
|
43
|
+
# read JSON object #
|
44
|
+
#################################
|
45
|
+
|
46
|
+
slashstarcomment = compile(r'/\*.*?\*/',DOTALL)
|
47
|
+
doubleslashcomment = compile(r'//.*\n')
|
48
|
+
|
49
|
+
def _Read(aString):
|
50
|
+
"""Use eval in a 'safe' way to turn javascript expression into
|
51
|
+
a python expression. Allow only True, False, and None in global
|
52
|
+
__builtins__, and since those map as true, false, null in
|
53
|
+
javascript, pass those as locals
|
54
|
+
"""
|
55
|
+
try:
|
56
|
+
result = eval(aString,
|
57
|
+
{"__builtins__":{'True':True,'False':False,'None':None}},
|
58
|
+
{'null':None,'true':True,'false':False})
|
59
|
+
except NameError:
|
60
|
+
raise ReadException, \
|
61
|
+
"Strings must be quoted. Could not read '%s'." % aString
|
62
|
+
except SyntaxError:
|
63
|
+
raise ReadException, \
|
64
|
+
"Syntax error. Could not read '%s'." % aString
|
65
|
+
return result
|
66
|
+
|
67
|
+
# badOperators is defined at the top of the module
|
68
|
+
|
69
|
+
# generate the regexes for math detection
|
70
|
+
regexes = {}
|
71
|
+
for operator in badOperators:
|
72
|
+
if operator in '+*':
|
73
|
+
# '+' and '*' need to be escaped with \ in re
|
74
|
+
regexes[operator,'numeric operation'] \
|
75
|
+
= compile(r"\d*\s*\%s|\%s\s*\d*" % (operator, operator))
|
76
|
+
else:
|
77
|
+
regexes[operator,'numeric operation'] \
|
78
|
+
= compile(r"\d*\s*%s|%s\s*\d*" % (operator, operator))
|
79
|
+
|
80
|
+
def _getStringState(aSequence):
|
81
|
+
"""return the list of required quote closures if the end of aString needs them
|
82
|
+
to close quotes.
|
83
|
+
"""
|
84
|
+
state = []
|
85
|
+
for k in aSequence:
|
86
|
+
if k in ['"',"'"]:
|
87
|
+
if state and k == state[-1]:
|
88
|
+
state.pop()
|
89
|
+
else:
|
90
|
+
state.append(k)
|
91
|
+
return state
|
92
|
+
|
93
|
+
def _sanityCheckMath(aString):
|
94
|
+
"""just need to check that, if there is a math operator in the
|
95
|
+
client's JSON, it is inside a quoted string. This is mainly to
|
96
|
+
keep client from successfully sending 'D0S'*9**9**9**9...
|
97
|
+
Return True if OK, False otherwise
|
98
|
+
"""
|
99
|
+
for operator in badOperators:
|
100
|
+
#first check, is it a possible math operation?
|
101
|
+
if regexes[(operator,'numeric operation')].search(aString) is not None:
|
102
|
+
# OK. possible math operation. get the operator's locations
|
103
|
+
getlocs = regexes[(operator,'numeric operation')].finditer(aString)
|
104
|
+
locs = [item.span() for item in getlocs]
|
105
|
+
halfStrLen = len(aString) / 2
|
106
|
+
#fortunately, this should be rare
|
107
|
+
for loc in locs:
|
108
|
+
exprStart = loc[0]
|
109
|
+
exprEnd = loc[1]
|
110
|
+
# We only need to know the char is within open quote
|
111
|
+
# status.
|
112
|
+
if exprStart <= halfStrLen:
|
113
|
+
teststr = aString[:exprStart]
|
114
|
+
else:
|
115
|
+
teststr = list(aString[exprEnd+1:])
|
116
|
+
teststr.reverse()
|
117
|
+
if not _getStringState(teststr):
|
118
|
+
return False
|
119
|
+
return True
|
120
|
+
|
121
|
+
def safeRead(aString):
|
122
|
+
"""turn the js into happier python and check for bad operations
|
123
|
+
before sending it to the interpreter
|
124
|
+
"""
|
125
|
+
# get rid of trailing null. Konqueror appends this, and the python
|
126
|
+
# interpreter balks when it is there.
|
127
|
+
CHR0 = chr(0)
|
128
|
+
while aString.endswith(CHR0):
|
129
|
+
aString = aString[:-1]
|
130
|
+
# strip leading and trailing whitespace
|
131
|
+
aString = aString.strip()
|
132
|
+
# zap /* ... */ comments
|
133
|
+
aString = slashstarcomment.sub('',aString)
|
134
|
+
# zap // comments
|
135
|
+
aString = doubleslashcomment.sub('',aString)
|
136
|
+
# here, we only check for the * operator as a DOS problem by default;
|
137
|
+
# additional operators may be excluded by editing badOperators
|
138
|
+
# at the top of the module
|
139
|
+
if _sanityCheckMath(aString):
|
140
|
+
return _Read(aString)
|
141
|
+
else:
|
142
|
+
raise ReadException, 'Unacceptable JSON expression: %s' % aString
|
143
|
+
|
144
|
+
read = safeRead
|
145
|
+
|
146
|
+
#################################
|
147
|
+
# write object as JSON #
|
148
|
+
#################################
|
149
|
+
|
150
|
+
#alwaysStripWhiteSpace is defined at the top of the module
|
151
|
+
|
152
|
+
tfnTuple = (('True','true'),('False','false'),('None','null'),)
|
153
|
+
|
154
|
+
def _replaceTrueFalseNone(aString):
|
155
|
+
"""replace True, False, and None with javascript counterparts"""
|
156
|
+
for k in tfnTuple:
|
157
|
+
if k[0] in aString:
|
158
|
+
aString = aString.replace(k[0],k[1])
|
159
|
+
return aString
|
160
|
+
|
161
|
+
def _handleCode(subStr,stripWhiteSpace):
|
162
|
+
"""replace True, False, and None with javascript counterparts if
|
163
|
+
appropriate, remove unicode u's, fix long L's, make tuples
|
164
|
+
lists, and strip white space if requested
|
165
|
+
"""
|
166
|
+
if 'e' in subStr:
|
167
|
+
#True, False, and None have 'e' in them. :)
|
168
|
+
subStr = (_replaceTrueFalseNone(subStr))
|
169
|
+
if stripWhiteSpace:
|
170
|
+
# re.sub might do a better job, but takes longer.
|
171
|
+
# Spaces are the majority of the whitespace, anyway...
|
172
|
+
subStr = subStr.replace(' ','')
|
173
|
+
if subStr[-1] in "uU":
|
174
|
+
#remove unicode u's
|
175
|
+
subStr = subStr[:-1]
|
176
|
+
if "L" in subStr:
|
177
|
+
#remove Ls from long ints
|
178
|
+
subStr = subStr.replace("L",'')
|
179
|
+
#do tuples as lists
|
180
|
+
if "(" in subStr:
|
181
|
+
subStr = subStr.replace("(",'[')
|
182
|
+
if ")" in subStr:
|
183
|
+
subStr = subStr.replace(")",']')
|
184
|
+
return subStr
|
185
|
+
|
186
|
+
# re for a double-quoted string that has a single-quote in it
|
187
|
+
# but no double-quotes and python punctuation after:
|
188
|
+
redoublequotedstring = compile(r'"[^"]*\'[^"]*"[,\]\}:\)]')
|
189
|
+
escapedSingleQuote = r"\'"
|
190
|
+
escapedDoubleQuote = r'\"'
|
191
|
+
|
192
|
+
def doQuotesSwapping(aString):
|
193
|
+
"""rewrite doublequoted strings with single quotes as singlequoted strings with
|
194
|
+
escaped single quotes"""
|
195
|
+
s = []
|
196
|
+
foundlocs = redoublequotedstring.finditer(aString)
|
197
|
+
prevend = 0
|
198
|
+
for loc in foundlocs:
|
199
|
+
start,end = loc.span()
|
200
|
+
s.append(aString[prevend:start])
|
201
|
+
tempstr = aString[start:end]
|
202
|
+
endchar = tempstr[-1]
|
203
|
+
ts1 = tempstr[1:-2]
|
204
|
+
ts1 = ts1.replace("'",escapedSingleQuote)
|
205
|
+
ts1 = "'%s'%s" % (ts1,endchar)
|
206
|
+
s.append(ts1)
|
207
|
+
prevend = end
|
208
|
+
s.append(aString[prevend:])
|
209
|
+
return ''.join(s)
|
210
|
+
|
211
|
+
def _pyexpr2jsexpr(aString, stripWhiteSpace):
|
212
|
+
"""Take advantage of python's formatting of string representations of
|
213
|
+
objects. Python always uses "'" to delimit strings. Except it doesn't when
|
214
|
+
there is ' in the string. Fix that, then, if we split
|
215
|
+
on that delimiter, we have a list that alternates non-string text with
|
216
|
+
string text. Since string text is already properly escaped, we
|
217
|
+
only need to replace True, False, and None in non-string text and
|
218
|
+
remove any unicode 'u's preceding string values.
|
219
|
+
|
220
|
+
if stripWhiteSpace is True, remove spaces, etc from the non-string
|
221
|
+
text.
|
222
|
+
"""
|
223
|
+
inSingleQuote = False
|
224
|
+
inDoubleQuote = False
|
225
|
+
#python will quote with " when there is a ' in the string,
|
226
|
+
#so fix that first
|
227
|
+
if redoublequotedstring.search(aString):
|
228
|
+
aString = doQuotesSwapping(aString)
|
229
|
+
marker = None
|
230
|
+
if escapedSingleQuote in aString:
|
231
|
+
#replace escaped single quotes with a marker
|
232
|
+
marker = markerBase = '|'
|
233
|
+
markerCount = 1
|
234
|
+
while marker in aString:
|
235
|
+
#if the marker is already there, make it different
|
236
|
+
markerCount += 1
|
237
|
+
marker = markerBase * markerCount
|
238
|
+
aString = aString.replace(escapedSingleQuote,marker)
|
239
|
+
|
240
|
+
#escape double-quotes
|
241
|
+
aString = aString.replace('"',escapedDoubleQuote)
|
242
|
+
#split the string on the real single-quotes
|
243
|
+
splitStr = aString.split("'")
|
244
|
+
outList = []
|
245
|
+
alt = True
|
246
|
+
for subStr in splitStr:
|
247
|
+
#if alt is True, non-string; do replacements
|
248
|
+
if alt:
|
249
|
+
subStr = _handleCode(subStr,stripWhiteSpace)
|
250
|
+
outList.append(subStr)
|
251
|
+
alt = not alt
|
252
|
+
result = '"'.join(outList)
|
253
|
+
if marker:
|
254
|
+
#put the escaped single-quotes back as "'"
|
255
|
+
result = result.replace(marker,"'")
|
256
|
+
return result
|
257
|
+
|
258
|
+
def write(obj, encoding="utf-8",stripWhiteSpace=alwaysStripWhiteSpace):
|
259
|
+
"""Represent the object as a string. Do any necessary fix-ups
|
260
|
+
with pyexpr2jsexpr"""
|
261
|
+
try:
|
262
|
+
#not really sure encode does anything here
|
263
|
+
aString = str(obj).encode(encoding)
|
264
|
+
except UnicodeEncodeError:
|
265
|
+
aString = obj.encode(encoding)
|
266
|
+
if isinstance(obj,basestring):
|
267
|
+
if '"' in aString:
|
268
|
+
aString = aString.replace(escapedDoubleQuote,'"')
|
269
|
+
result = '"%s"' % aString.replace('"',escapedDoubleQuote)
|
270
|
+
else:
|
271
|
+
result = '"%s"' % aString
|
272
|
+
else:
|
273
|
+
result = _pyexpr2jsexpr(aString,stripWhiteSpace).encode(encoding)
|
274
|
+
return result
|
275
|
+
|
276
|
+
class ReadException(Exception):
|
277
|
+
pass
|
278
|
+
|
279
|
+
class WriteException(Exception):
|
280
|
+
pass
|