##// END OF EJS Templates
simplify join
Kyle Kelley -
Show More
@@ -1,332 +1,331 b''
1 #!/usr/bin/python
1 #!/usr/bin/python
2 """Utility function for installing MathJax javascript library into
2 """Utility function for installing MathJax javascript library into
3 the notebook's 'static' directory, for offline use.
3 the notebook's 'static' directory, for offline use.
4
4
5 Authors:
5 Authors:
6
6
7 * Min RK
7 * Min RK
8 * Mark Sienkiewicz
8 * Mark Sienkiewicz
9 * Matthias Bussonnier
9 * Matthias Bussonnier
10
10
11 To download and install MathJax:
11 To download and install MathJax:
12
12
13 From Python:
13 From Python:
14
14
15 >>> from IPython.external.mathjax import install_mathjax
15 >>> from IPython.external.mathjax import install_mathjax
16 >>> install_mathjax()
16 >>> install_mathjax()
17
17
18 From the command line:
18 From the command line:
19
19
20 $ python -m IPython.external.mathjax
20 $ python -m IPython.external.mathjax
21
21
22 To a specific profile:
22 To a specific profile:
23
23
24 $ python -m IPython.external.mathjax --profile=research
24 $ python -m IPython.external.mathjax --profile=research
25
25
26 To install MathJax from a file you have already downloaded:
26 To install MathJax from a file you have already downloaded:
27
27
28 $ python -m IPython.external.mathjax mathjax-xxx.tar.gz
28 $ python -m IPython.external.mathjax mathjax-xxx.tar.gz
29 $ python -m IPython.external.mathjax mathjax-xxx.zip
29 $ python -m IPython.external.mathjax mathjax-xxx.zip
30
30
31 It will not install MathJax if it is already there. Use -r to
31 It will not install MathJax if it is already there. Use -r to
32 replace the existing copy of MathJax.
32 replace the existing copy of MathJax.
33
33
34 To find the directory where IPython would like MathJax installed:
34 To find the directory where IPython would like MathJax installed:
35
35
36 $ python -m IPython.external.mathjax -d
36 $ python -m IPython.external.mathjax -d
37
37
38 """
38 """
39
39
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Copyright (C) 2008-2011 The IPython Development Team
42 # Copyright (C) 2008-2011 The IPython Development Team
43 #
43 #
44 # Distributed under the terms of the BSD License. The full license is in
44 # Distributed under the terms of the BSD License. The full license is in
45 # the file COPYING, distributed as part of this software.
45 # the file COPYING, distributed as part of this software.
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Imports
50 # Imports
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 import os
53 import os
54 import shutil
54 import shutil
55 import sys
55 import sys
56 import tarfile
56 import tarfile
57 import urllib2
57 import urllib2
58 import zipfile
58 import zipfile
59
59
60
60
61 from IPython.utils.path import locate_profile
61 from IPython.utils.path import locate_profile
62 from IPython.external import argparse
62 from IPython.external import argparse
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 #
64 #
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67 # Where mathjax will be installed.
67 # Where mathjax will be installed.
68
68
69 static = os.path.join(locate_profile('default'), 'static')
69 static = os.path.join(locate_profile('default'), 'static')
70 default_dest = os.path.join(static, 'mathjax')
70 default_dest = os.path.join(static, 'mathjax')
71
71
72 ##
72 ##
73
73
74 # Test for access to install mathjax.
74 # Test for access to install mathjax.
75
75
76 def check_perms(dest, replace=False):
76 def check_perms(dest, replace=False):
77 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
77 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
78 components = dest.split(os.path.sep)
78 components = dest.split(os.path.sep)
79 subpaths = [ os.path.sep+os.path.sep.join(components[1:i]) for i in range(1,len(components))]
79 subpaths = [ os.path.sep+os.path.sep.join(components[1:i]) for i in range(1,len(components))]
80
80
81 existing_path = filter(os.path.exists, subpaths)
81 existing_path = filter(os.path.exists, subpaths)
82 last_writable = existing_path[-1]
82 last_writable = existing_path[-1]
83 if not os.access(last_writable, os.W_OK):
83 if not os.access(last_writable, os.W_OK):
84 raise IOError("Need have write access to %s" % parent)
84 raise IOError("Need have write access to %s" % parent)
85 not_existing = [ path for path in subpaths if path not in existing_path]
85 not_existing = [ path for path in subpaths if path not in existing_path]
86 # subfolder we will create, will obviously be writable
86 # subfolder we will create, will obviously be writable
87 # should we still considere checking separately that
87 # should we still considere checking separately that
88 # ipython profiles have been created ?
88 # ipython profiles have been created ?
89 for folder in not_existing:
89 for folder in not_existing:
90 os.mkdir(folder)
90 os.mkdir(folder)
91
91
92 if os.path.exists(dest):
92 if os.path.exists(dest):
93 if replace:
93 if replace:
94 if not os.access(dest, os.W_OK):
94 if not os.access(dest, os.W_OK):
95 raise IOError("Need have write access to %s" % dest)
95 raise IOError("Need have write access to %s" % dest)
96 print "removing previous MathJax install"
96 print "removing previous MathJax install"
97 shutil.rmtree(dest)
97 shutil.rmtree(dest)
98 return True
98 return True
99 else:
99 else:
100 print "offline MathJax apparently already installed"
100 print "offline MathJax apparently already installed"
101 return False
101 return False
102 else :
102 else :
103 return True
103 return True
104
104
105 ##
105 ##
106
106
107 def extract_tar( fd, dest ) :
107 def extract_tar( fd, dest ) :
108 # use 'r|gz' stream mode, because socket file-like objects can't seek:
108 # use 'r|gz' stream mode, because socket file-like objects can't seek:
109 tar = tarfile.open(fileobj=fd, mode='r|gz')
109 tar = tarfile.open(fileobj=fd, mode='r|gz')
110
110
111 # we just happen to know that the first entry in the mathjax
111 # we just happen to know that the first entry in the mathjax
112 # archive is the directory that the remaining members are in.
112 # archive is the directory that the remaining members are in.
113 topdir = tar.firstmember.path
113 topdir = tar.firstmember.path
114
114
115 # extract the archive (contains a single directory) to the static/ directory
115 # extract the archive (contains a single directory) to the static/ directory
116 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
116 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
117 tar.extractall(parent)
117 tar.extractall(parent)
118
118
119 # it will be mathjax-MathJax-<sha>, rename to just mathjax
119 # it will be mathjax-MathJax-<sha>, rename to just mathjax
120 os.rename(os.path.join(parent, topdir), dest)
120 os.rename(os.path.join(parent, topdir), dest)
121
121
122 ##
122 ##
123
123
124 def extract_zip( fd, dest ) :
124 def extract_zip( fd, dest ) :
125 z = zipfile.ZipFile( fd, 'r' )
125 z = zipfile.ZipFile( fd, 'r' )
126
126
127 # we just happen to know that the first entry in the mathjax
127 # we just happen to know that the first entry in the mathjax
128 # archive is the directory that the remaining members are in.
128 # archive is the directory that the remaining members are in.
129 topdir = z.namelist()[0]
129 topdir = z.namelist()[0]
130
130
131 # extract the archive (contains a single directory) to the static/ directory
131 # extract the archive (contains a single directory) to the static/ directory
132 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
132 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
133 z.extractall( parent )
133 z.extractall( parent )
134
134
135 # it will be mathjax-MathJax-<sha>, rename to just mathjax
135 # it will be mathjax-MathJax-<sha>, rename to just mathjax
136 d = os.path.join(parent, topdir)
136 d = os.path.join(parent, topdir)
137 print d
137 print d
138 os.rename(os.path.join(parent, topdir), dest)
138 os.rename(os.path.join(parent, topdir), dest)
139
139
140 ##
140 ##
141
141
142 def install_mathjax(tag='v2.0', dest=default_dest, replace=False, file=None, extractor=extract_tar ):
142 def install_mathjax(tag='v2.0', dest=default_dest, replace=False, file=None, extractor=extract_tar ):
143 """Download and/or install MathJax for offline use.
143 """Download and/or install MathJax for offline use.
144
144
145 This will install mathjax to the 'static' dir in the IPython notebook
145 This will install mathjax to the 'static' dir in the IPython notebook
146 package, so it will fail if the caller does not have write access
146 package, so it will fail if the caller does not have write access
147 to that location.
147 to that location.
148
148
149 MathJax is a ~15MB download, and ~150MB installed.
149 MathJax is a ~15MB download, and ~150MB installed.
150
150
151 Parameters
151 Parameters
152 ----------
152 ----------
153
153
154 replace : bool [False]
154 replace : bool [False]
155 Whether to remove and replace an existing install.
155 Whether to remove and replace an existing install.
156 dest : str [path to default profile]
156 dest : str [path to default profile]
157 Where to locally install mathjax
157 Where to locally install mathjax
158 tag : str ['v2.0']
158 tag : str ['v2.0']
159 Which tag to download. Default is 'v2.0', the current stable release,
159 Which tag to download. Default is 'v2.0', the current stable release,
160 but alternatives include 'v1.1a' and 'master'.
160 but alternatives include 'v1.1a' and 'master'.
161 file : file like object [ defualt to content of https://github.com/mathjax/MathJax/tarball/#{tag}]
161 file : file like object [ defualt to content of https://github.com/mathjax/MathJax/tarball/#{tag}]
162 File handle from which to untar/unzip/... mathjax
162 File handle from which to untar/unzip/... mathjax
163 extractor : function
163 extractor : function
164 Method tu use to untar/unzip/... `file`
164 Method tu use to untar/unzip/... `file`
165 """
165 """
166 if not check_perms(dest, replace) :
166 if not check_perms(dest, replace) :
167 return
167 return
168
168
169 if file is None :
169 if file is None :
170 # download mathjax
170 # download mathjax
171 mathjax_url = "https://github.com/mathjax/MathJax/tarball/%s" % tag
171 mathjax_url = "https://github.com/mathjax/MathJax/tarball/%s" % tag
172 print "Downloading mathjax source from %s" % mathjax_url
172 print "Downloading mathjax source from %s" % mathjax_url
173 response = urllib2.urlopen(mathjax_url)
173 response = urllib2.urlopen(mathjax_url)
174 file = response.fp
174 file = response.fp
175
175
176 print "Extracting to %s" % dest
176 print "Extracting to %s" % dest
177 extractor( file, dest )
177 extractor( file, dest )
178
178
179 ##
179 ##
180
180
181 def test_func( remove, dest) :
181 def test_func( remove, dest) :
182 """See if mathjax appears to be installed correctly"""
182 """See if mathjax appears to be installed correctly"""
183 status = 0
183 status = 0
184 if not os.path.isdir( dest ) :
184 if not os.path.isdir( dest ) :
185 print "%s directory not found" % dest
185 print "%s directory not found" % dest
186 status = 1
186 status = 1
187 if not os.path.exists( dest + "/MathJax.js" ) :
187 if not os.path.exists( dest + "/MathJax.js" ) :
188 print "MathJax.js not present in %s" % dest
188 print "MathJax.js not present in %s" % dest
189 status = 1
189 status = 1
190 print "ok"
190 print "ok"
191 if remove and os.path.exists(dest):
191 if remove and os.path.exists(dest):
192 shutil.rmtree( dest )
192 shutil.rmtree( dest )
193 return status
193 return status
194
194
195 ##
195 ##
196
196
197 def main() :
197 def main() :
198 # This main is just simple enough that it is not worth the
198 # This main is just simple enough that it is not worth the
199 # complexity of argparse
199 # complexity of argparse
200
200
201 # What directory is mathjax in?
201 # What directory is mathjax in?
202 parser = argparse.ArgumentParser(
202 parser = argparse.ArgumentParser(
203 description="""Install mathjax from internet or local archive""",
203 description="""Install mathjax from internet or local archive""",
204 )
204 )
205
205
206 parser.add_argument(
206 parser.add_argument(
207 '-p',
207 '-p',
208 '--profile',
208 '--profile',
209 default='default',
209 default='default',
210 help='profile to install MathJax to (default is default)')
210 help='profile to install MathJax to (default is default)')
211
211
212 parser.add_argument(
212 parser.add_argument(
213 '-i',
213 '-i',
214 '--install-dir',
214 '--install-dir',
215 help='custom installation directory')
215 help='custom installation directory')
216
216
217 parser.add_argument(
217 parser.add_argument(
218 '-d',
218 '-d',
219 '--dest',
219 '--dest',
220 action='store_true',
220 action='store_true',
221 help='print where current mathjax would be installed and exit')
221 help='print where current mathjax would be installed and exit')
222 parser.add_argument(
222 parser.add_argument(
223 '-r',
223 '-r',
224 '--replace',
224 '--replace',
225 action='store_true',
225 action='store_true',
226 help='Whether to replace current mathjax if it already exists')
226 help='Whether to replace current mathjax if it already exists')
227 parser.add_argument(
227 parser.add_argument(
228 '-t',
228 '-t',
229 '--test',
229 '--test',
230 action='store_true')
230 action='store_true')
231 parser.add_argument('tarball',
231 parser.add_argument('tarball',
232 help="the local tar/zip-ball containing mathjax",
232 help="the local tar/zip-ball containing mathjax",
233 nargs='?',
233 nargs='?',
234 metavar='tarball')
234 metavar='tarball')
235
235
236 pargs = parser.parse_args()
236 pargs = parser.parse_args()
237
237
238 if pargs.install_dir:
238 if pargs.install_dir:
239 # Explicit install_dir overrides profile
239 # Explicit install_dir overrides profile
240 dest = pargs.install_dir
240 dest = pargs.install_dir
241 else:
241 else:
242 profile = pargs.profile
242 profile = pargs.profile
243 static = os.path.join(locate_profile(profile), 'static')
243 dest = os.path.join(locate_profile(profile), 'static', 'mathjax')
244 dest = os.path.join(static, 'mathjax')
245
244
246 if pargs.dest :
245 if pargs.dest :
247 print dest
246 print dest
248 return
247 return
249
248
250 # remove/replace existing mathjax?
249 # remove/replace existing mathjax?
251 if pargs.replace :
250 if pargs.replace :
252 replace = True
251 replace = True
253 else :
252 else :
254 replace = False
253 replace = False
255
254
256 # undocumented test interface
255 # undocumented test interface
257 if pargs.test :
256 if pargs.test :
258 return test_func( replace, dest)
257 return test_func( replace, dest)
259
258
260 # do it
259 # do it
261 if pargs.tarball :
260 if pargs.tarball :
262 fname = pargs.tarball
261 fname = pargs.tarball
263
262
264 # automatically detect zip/tar - could do something based
263 # automatically detect zip/tar - could do something based
265 # on file content, but really not cost-effective here.
264 # on file content, but really not cost-effective here.
266 if fname.endswith('.zip') :
265 if fname.endswith('.zip') :
267 extractor = extract_zip
266 extractor = extract_zip
268 else :
267 else :
269 extractor = extract_tar
268 extractor = extract_tar
270 # do it
269 # do it
271 install_mathjax(file=open(fname, "r"), replace=replace, extractor=extractor, dest=dest )
270 install_mathjax(file=open(fname, "r"), replace=replace, extractor=extractor, dest=dest )
272 else:
271 else:
273 install_mathjax(replace=replace, dest=dest)
272 install_mathjax(replace=replace, dest=dest)
274
273
275
274
276 if __name__ == '__main__' :
275 if __name__ == '__main__' :
277 sys.exit(main())
276 sys.exit(main())
278
277
279 __all__ = ['install_mathjax', 'main', 'dest']
278 __all__ = ['install_mathjax', 'main', 'dest']
280
279
281 """
280 """
282 Test notes:
281 Test notes:
283
282
284 IPython uses IPython.testing.iptest as a custom test controller
283 IPython uses IPython.testing.iptest as a custom test controller
285 (though it is based on nose). It might be possible to fit automatic
284 (though it is based on nose). It might be possible to fit automatic
286 tests of installation into that framework, but it looks awkward to me.
285 tests of installation into that framework, but it looks awkward to me.
287 So, here is a manual procedure for testing this automatic installer.
286 So, here is a manual procedure for testing this automatic installer.
288
287
289 Mark Sienkiewicz, 2012-08-06
288 Mark Sienkiewicz, 2012-08-06
290 first 8 letters of my last name @ stsci.edu
289 first 8 letters of my last name @ stsci.edu
291
290
292 # remove mathjax from the installed ipython instance
291 # remove mathjax from the installed ipython instance
293 # IOError ok if mathjax was never installed yet.
292 # IOError ok if mathjax was never installed yet.
294
293
295 python -m IPython.external.mathjax --test -r
294 python -m IPython.external.mathjax --test -r
296
295
297 # download and install mathjax from command line:
296 # download and install mathjax from command line:
298
297
299 python -m IPython.external.mathjax
298 python -m IPython.external.mathjax
300 python -m IPython.external.mathjax --test -r
299 python -m IPython.external.mathjax --test -r
301
300
302 # download and install from within python
301 # download and install from within python
303
302
304 python -c "from IPython.external.mathjax import install_mathjax; install_mathjax()"
303 python -c "from IPython.external.mathjax import install_mathjax; install_mathjax()"
305 python -m IPython.external.mathjax --test -r
304 python -m IPython.external.mathjax --test -r
306
305
307 # view http://www.mathjax.org/download/ in your browser
306 # view http://www.mathjax.org/download/ in your browser
308 # save-as the link for MathJax-2.0 near the bottom of the page.
307 # save-as the link for MathJax-2.0 near the bottom of the page.
309 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.zip
308 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.zip
310
309
311 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.zip
310 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.zip
312 python -m IPython.external.mathjax --test -r
311 python -m IPython.external.mathjax --test -r
313
312
314 # download https://github.com/mathjax/MathJax/tarball/v2.0 in your browser
313 # download https://github.com/mathjax/MathJax/tarball/v2.0 in your browser
315 # (this is the url used internally by install_mathjax)
314 # (this is the url used internally by install_mathjax)
316 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.tar.gz
315 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.tar.gz
317
316
318 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
317 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
319
318
320 python -m IPython.external.mathjax --test
319 python -m IPython.external.mathjax --test
321 # note no -r
320 # note no -r
322
321
323 # install it again while it is already there
322 # install it again while it is already there
324
323
325 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
324 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
326 # says "offline MathJax apparently already installed"
325 # says "offline MathJax apparently already installed"
327
326
328 python -m IPython.external.mathjax ~/mathjax-MathJax-v2.0-20-g07669ac.tar.gz
327 python -m IPython.external.mathjax ~/mathjax-MathJax-v2.0-20-g07669ac.tar.gz
329 python -m IPython.external.mathjax --test
328 python -m IPython.external.mathjax --test
330
329
331
330
332 """
331 """
General Comments 0
You need to be logged in to leave comments. Login now