├── .gitignore ├── README.md ├── demo.ipynb ├── idl_kernel.py ├── setup.py └── snapshot.pro /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | eggs/ 15 | lib/ 16 | lib64/ 17 | parts/ 18 | sdist/ 19 | var/ 20 | *.egg-info/ 21 | .installed.cfg 22 | *.egg 23 | 24 | # PyInstaller 25 | # Usually these files are written by a python script from a template 26 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 27 | *.manifest 28 | *.spec 29 | 30 | # Installer logs 31 | pip-log.txt 32 | pip-delete-this-directory.txt 33 | 34 | # Unit test / coverage reports 35 | htmlcov/ 36 | .tox/ 37 | .coverage 38 | .cache 39 | nosetests.xml 40 | coverage.xml 41 | 42 | # Translations 43 | *.mo 44 | *.pot 45 | 46 | # Django stuff: 47 | *.log 48 | 49 | # Sphinx documentation 50 | docs/_build/ 51 | 52 | # PyBuilder 53 | target/ 54 | 55 | # IPython 56 | .ipynb_checkpoints 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #This package is no longer maintained since IDL now has an [official Jupyter kernel](https://www.harrisgeospatial.com/docs/IDL_Kernel.html) 2 | #IDL/GDL kernel for IPython/Jupyter 3 | 4 | Demo [Notebook](http://nbviewer.ipython.org/github/lstagner/idl_kernel/blob/master/demo.ipynb) 5 | 6 | To install: 7 | 8 | This requires IPython >3.0 and Pexpect 3.3 9 | 10 | ``` 11 | python setup.py install --prefix=~/.local 12 | ``` 13 | 14 | This should make an IDL directory containing the kernelspec in the ~/.ipython/kernels directory. 15 | 16 | To run: 17 | ``` 18 | ipython console --kernel IDL 19 | ``` 20 | or 21 | ``` 22 | ipython qtconsole --kernel IDL 23 | ``` 24 | or 25 | ``` 26 | ipython notebook 27 | #Select kernel from dropdown menu 28 | ``` 29 | 30 | 31 | -------------------------------------------------------------------------------- /demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# IDL Kernel Demo" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "This notebook demostrates the current capability of the IDL IPython/Jupyter Kernel" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Basic Input & Output" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 1, 27 | "metadata": { 28 | "collapsed": false 29 | }, 30 | "outputs": [ 31 | { 32 | "name": "stdout", 33 | "output_type": "stream", 34 | "text": [ 35 | "A INT = 1\r\n", 36 | "B INT = 2\r\n", 37 | "STR STRING = 'Hello, World!'\r\n", 38 | "ARR INT = Array[5]\r\n" 39 | ] 40 | } 41 | ], 42 | "source": [ 43 | "a = 1\n", 44 | "b = 2\n", 45 | "arr = indgen(5)\n", 46 | "str = \"Hello, World!\"\n", 47 | "help,a,b,str,arr" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 2, 53 | "metadata": { 54 | "collapsed": false 55 | }, 56 | "outputs": [ 57 | { 58 | "name": "stdout", 59 | "output_type": "stream", 60 | "text": [ 61 | "Hello, World!\r\n" 62 | ] 63 | } 64 | ], 65 | "source": [ 66 | "print,str" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "## Defining Functions & Procedures" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 3, 79 | "metadata": { 80 | "collapsed": false 81 | }, 82 | "outputs": [ 83 | { 84 | "name": "stdout", 85 | "output_type": "stream", 86 | "text": [] 87 | } 88 | ], 89 | "source": [ 90 | "FUNCTION mysin, x\n", 91 | " return, sin(x)\n", 92 | "END" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 4, 98 | "metadata": { 99 | "collapsed": false 100 | }, 101 | "outputs": [ 102 | { 103 | "name": "stdout", 104 | "output_type": "stream", 105 | "text": [ 106 | " 0.90930\r\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "print, mysin(2)" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 5, 117 | "metadata": { 118 | "collapsed": false 119 | }, 120 | "outputs": [ 121 | { 122 | "name": "stdout", 123 | "output_type": "stream", 124 | "text": [] 125 | } 126 | ], 127 | "source": [ 128 | "PRO hello_world\n", 129 | " print,\"Hello, World!\"\n", 130 | "END" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 6, 136 | "metadata": { 137 | "collapsed": false 138 | }, 139 | "outputs": [ 140 | { 141 | "name": "stdout", 142 | "output_type": "stream", 143 | "text": [ 144 | "Hello, World!\r\n" 145 | ] 146 | } 147 | ], 148 | "source": [ 149 | "hello_world" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "## Inline Plots" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 7, 162 | "metadata": { 163 | "collapsed": false 164 | }, 165 | "outputs": [ 166 | { 167 | "name": "stdout", 168 | "output_type": "stream", 169 | "text": [] 170 | } 171 | ], 172 | "source": [ 173 | ";;This enables inline plotting\n", 174 | "!inline=1" 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": 8, 180 | "metadata": { 181 | "collapsed": false 182 | }, 183 | "outputs": [ 184 | { 185 | "data": { 186 | "image/png": [ 187 | "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" 188 | ] 189 | }, 190 | "metadata": {}, 191 | "output_type": "display_data" 192 | }, 193 | { 194 | "name": "stdout", 195 | "output_type": "stream", 196 | "text": [] 197 | } 198 | ], 199 | "source": [ 200 | "x = 2*!PI*0.01*indgen(100)\n", 201 | "y1 = sin(x)\n", 202 | "y2 = cos(x)\n", 203 | "loadct,39\n", 204 | "window,xsize=800,ysize=500\n", 205 | "plot,x,y1,title='Trig Functions',xtitle='Radians',ytitle='Amplitude',xrange=[0,6],charsize=1.5,background=255,color=0\n", 206 | "oplot,x,y2,color=50" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": null, 212 | "metadata": { 213 | "collapsed": false 214 | }, 215 | "outputs": [], 216 | "source": [] 217 | } 218 | ], 219 | "metadata": { 220 | "kernelspec": { 221 | "display_name": "IDL", 222 | "name": "idl" 223 | }, 224 | "language_info": { 225 | "codemirror_mode": "idl", 226 | "file_extension": ".pro", 227 | "mimetype": "text/x-idl", 228 | "name": "idl" 229 | } 230 | }, 231 | "nbformat": 4, 232 | "nbformat_minor": 0 233 | } -------------------------------------------------------------------------------- /idl_kernel.py: -------------------------------------------------------------------------------- 1 | from IPython.kernel.zmq.kernelbase import Kernel 2 | from IPython.utils.path import locate_profile 3 | from IPython.core.displaypub import publish_display_data 4 | from pexpect import replwrap,EOF,spawn 5 | 6 | import signal 7 | from subprocess import check_output 8 | import tempfile 9 | import re 10 | import os 11 | from glob import glob 12 | from shutil import rmtree 13 | from base64 import b64encode 14 | from distutils.spawn import find_executable 15 | 16 | __version__ = '0.4' 17 | 18 | version_pat = re.compile(r'Version (\d+(\.\d+)+)') 19 | 20 | class IDLKernel(Kernel): 21 | implementation = 'idl_kernel' 22 | implementation_version = __version__ 23 | language = 'IDL' 24 | @property 25 | def language_version(self): 26 | try: 27 | m = version_pat.search(self.banner) 28 | return m.group(1) 29 | except: 30 | return "Version ?.?" 31 | 32 | _banner = None 33 | @property 34 | def banner(self): 35 | if self._banner is None: 36 | try: 37 | if os.path.basename(self._executable) == 'idl': 38 | self._banner = check_output([self._executable, '-e','"print,string(0B)"']).decode('utf-8') 39 | else: 40 | self._banner = check_output([self._executable, '--version']).decode('utf-8') 41 | except: 42 | self._banner = '' 43 | 44 | return self._banner 45 | 46 | language_info = {'name': 'idl', 47 | 'codemirror_mode': 'idl', 48 | 'mimetype': 'text/x-idl', 49 | 'file_extension': '.pro'} 50 | 51 | def __init__(self, **kwargs): 52 | Kernel.__init__(self, **kwargs) 53 | self._start_idl() 54 | 55 | try: 56 | self.hist_file = os.path.join(locate_profile(),'idl_kernel.hist') 57 | except: 58 | self.hist_file = None 59 | self.log.warn('No default profile found, history unavailable') 60 | 61 | self.max_hist_cache = 1000 62 | self.hist_cache = [] 63 | 64 | def _start_idl(self): 65 | # Signal handlers are inherited by forked processes, and we can't easily 66 | # reset it from the subprocess. Since kernelapp ignores SIGINT except in 67 | # message handlers, we need to temporarily reset the SIGINT handler here 68 | # so that IDL and its children are interruptible. 69 | sig = signal.signal(signal.SIGINT, signal.SIG_DFL) 70 | try: 71 | self._executable = find_executable("idl") 72 | self._child = spawn(self._executable,timeout = 300) 73 | self.idlwrapper = replwrap.REPLWrapper(self._child,u"IDL> ",None) 74 | except: 75 | self._executable = find_executable("gdl") 76 | self._child = spawn(self._executable,timeout = 300) 77 | self.idlwrapper = replwrap.REPLWrapper(self._child,u"GDL> ",None) 78 | finally: 79 | signal.signal(signal.SIGINT, sig) 80 | 81 | self.idlwrapper.run_command("!quiet=1 & defsysv,'!inline',0 & !more=0".rstrip(), timeout=None) 82 | # Compile IDL routines/functions 83 | dirname = os.path.dirname(os.path.abspath(__file__)) 84 | self.idlwrapper.run_command(".compile "+dirname+"/snapshot.pro",timeout=None) 85 | 86 | def do_execute(self, code, silent, store_history=True, user_expressions=None, 87 | allow_stdin=False): 88 | 89 | if not code.strip(): 90 | return {'status': 'ok', 'execution_count': self.execution_count, 91 | 'payloads': [], 'user_expressions': {}} 92 | 93 | elif (code.strip() == 'exit' or code.strip() == 'quit'): 94 | self.do_shutdown(False) 95 | return {'status':'abort','execution_count':self.execution_count} 96 | 97 | elif (code.strip().startswith('.') or code.strip().startswith('@')): 98 | # This is a IDL Executive command 99 | output = self.idlwrapper.run_command(code.strip(), timeout=None) 100 | 101 | if os.path.basename(self._executable) == 'idl': 102 | output = '\n'.join(output.splitlines()[1::])+'\n' 103 | 104 | if not silent: 105 | stream_content = {'name': 'stdout', 'text':output} 106 | self.send_response(self.iopub_socket, 'stream', stream_content) 107 | 108 | return {'status': 'ok', 'execution_count': self.execution_count, 109 | 'payloads': [], 'user_expressions': {}} 110 | 111 | if code.strip() and store_history: 112 | self.hist_cache.append(code.strip()) 113 | 114 | interrupted = False 115 | tfile_code = tempfile.NamedTemporaryFile(mode='w+t',dir=os.path.expanduser("~")) 116 | tfile_post = tempfile.NamedTemporaryFile(mode='w+t',dir=os.path.expanduser("~")) 117 | plot_dir = tempfile.mkdtemp(dir=os.path.expanduser("~")) 118 | plot_format = 'png' 119 | 120 | postcall = """ 121 | device,window_state=winds_arefgij 122 | if !inline and total(winds_arefgij) ne 0 then begin 123 | w_CcjqL6MA = where(winds_arefgij ne 0,nw_CcjqL6MA) 124 | for i_KEv8eW6E=0,nw_CcjqL6MA-1 do begin 125 | wset, w_CcjqL6MA[i_KEv8eW6E] 126 | outfile_c5BXq4dV = '%(plot_dir)s/__fig'+strtrim(i_KEv8eW6E,2)+'.png' 127 | ii_rsApk4JS = snapshot(outfile_c5BXq4dV) 128 | wdelete 129 | endfor 130 | endif 131 | end 132 | """ % locals() 133 | 134 | try: 135 | tfile_code.file.write(code.rstrip()+"\na_adfadfw=1\nend") 136 | tfile_code.file.close() 137 | tfile_post.file.write(postcall.rstrip()) 138 | tfile_post.file.close() 139 | output = self.idlwrapper.run_command(".run "+tfile_code.name, timeout=None) 140 | self.idlwrapper.run_command(".run "+tfile_post.name,timeout=None) 141 | 142 | # IDL annoying prints out ".run tmp..." command this removes it 143 | if os.path.basename(self._executable) == 'idl': 144 | output = '\n'.join(output.splitlines()[1::])+'\n' 145 | 146 | # Publish images if there are any 147 | images = [open(imgfile, 'rb').read() for imgfile in glob("%s/*.png" % plot_dir)] 148 | 149 | display_data=[] 150 | 151 | for image in images: 152 | display_data.append({'image/png': b64encode(image).decode('ascii')}) 153 | 154 | for data in display_data: 155 | self.send_response(self.iopub_socket, 'display_data',{'data':data,'metadata':{}}) 156 | except KeyboardInterrupt: 157 | self.idlwrapper.child.sendintr() 158 | interrupted = True 159 | self.idlwrapper._expect_prompt() 160 | output = self.idlwrapper.child.before 161 | except EOF: 162 | output = self.idlwrapper.child.before + 'Restarting IDL' 163 | self._start_idl() 164 | finally: 165 | tfile_code.close() 166 | tfile_post.close() 167 | rmtree(plot_dir) 168 | 169 | if not silent: 170 | stream_content = {'name': 'stdout', 'text':output} 171 | self.send_response(self.iopub_socket, 'stream', stream_content) 172 | 173 | if interrupted: 174 | return {'status': 'abort', 'execution_count': self.execution_count} 175 | 176 | try: 177 | exitcode = int(self.run_command('print,0').rstrip()) 178 | except Exception: 179 | exitcode = 1 180 | 181 | if exitcode: 182 | return {'status': 'error', 'execution_count': self.execution_count, 183 | 'ename': '', 'evalue': str(exitcode), 'traceback': []} 184 | else: 185 | return {'status': 'ok', 'execution_count': self.execution_count, 186 | 'payloads': [], 'user_expressions': {}} 187 | 188 | def do_history(self, hist_access_type, output, raw, session=None, 189 | start=None, stop=None, n=None, pattern=None, unique=False): 190 | 191 | if not self.hist_file: 192 | return {'history': []} 193 | 194 | if not os.path.exists(self.hist_file): 195 | with open(self.hist_file, 'wb') as f: 196 | f.write('') 197 | 198 | with open(self.hist_file, 'rb') as f: 199 | history = f.readlines() 200 | 201 | history = history[:self.max_hist_cache] 202 | self.hist_cache = history 203 | self.log.debug('**HISTORY:') 204 | self.log.debug(history) 205 | history = [(None, None, h) for h in history] 206 | 207 | return {'history': history} 208 | 209 | def do_shutdown(self, restart): 210 | self.log.debug("**Shutting down") 211 | 212 | self.idlwrapper.child.kill(signal.SIGKILL) 213 | 214 | if self.hist_file: 215 | with open(self.hist_file,'wb') as f: 216 | data = '\n'.join(self.hist_cache[-self.max_hist_cache:]) 217 | f.write(data.encode('utf-8')) 218 | 219 | return {'status':'ok', 'restart':restart} 220 | 221 | if __name__ == '__main__': 222 | from IPython.kernel.zmq.kernelapp import IPKernelApp 223 | IPKernelApp.launch_instance(kernel_class=IDLKernel) 224 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.command.install import install 3 | import json 4 | import os.path 5 | import sys 6 | 7 | kernel_json = {"argv":[sys.executable,"-m","idl_kernel","-f","{connection_file}"], 8 | "display_name":"IDL", 9 | "language":"IDL", 10 | "codemirror_mode":"idl"} 11 | 12 | class install_with_kernelspec(install): 13 | def run(self): 14 | install.run(self) 15 | 16 | from IPython.kernel.kernelspec import KernelSpecManager 17 | from IPython.utils.path import ensure_dir_exists 18 | destdir = os.path.join(KernelSpecManager().user_kernel_dir,'IDL') 19 | ensure_dir_exists(destdir) 20 | with open(os.path.join(destdir,'kernel.json'),'w') as f: 21 | json.dump(kernel_json,f,sort_keys=True) 22 | 23 | 24 | with open('README.md') as f: 25 | readme = f.read() 26 | 27 | svem_flag = '--single-version-externally-managed' 28 | if svem_flag in sys.argv: 29 | sys.argv.remove(svem_flag) 30 | 31 | setup(name='IDL_kernel', 32 | version='0.4', 33 | description='A IDL kernel for IPython', 34 | long_description=readme, 35 | author='Luke Stagner', 36 | url='https://github.com/lstagner/idl_kernel', 37 | py_modules=['idl_kernel'], 38 | cmdclass={'install': install_with_kernelspec}, 39 | install_requires=['pexpect>=3.3','IPython >= 3.0'], 40 | classifiers = [ 41 | 'Framework :: Jupyter', 42 | 'License :: OSI Approved :: BSD License', 43 | 'Programming Language :: Python :: 3', 44 | 'Topic :: System :: Shells', 45 | ] 46 | ) 47 | -------------------------------------------------------------------------------- /snapshot.pro: -------------------------------------------------------------------------------- 1 | ;Function modified from http://www.idlcoyote.com/programs/cgsnapshot.pro 2 | FUNCTION snapshot, filename, xstart=xstart, ystart=ystart, ncols=ncols, nrows=nrows, $ 3 | Colors=colors, $ 4 | Order=order, $ 5 | POSITION=position, $ 6 | True=true, $ 7 | WID=wid, $ 8 | _Ref_Extra=extra 9 | 10 | 11 | ; Error handling. 12 | Catch, theError 13 | IF theError NE 0 THEN BEGIN 14 | Catch, /Cancel 15 | print,"SNAPSHOT ERROR: ",theError 16 | IF N_Elements(thisWindow) EQ 0 THEN RETURN, -1 17 | IF thisWindow GE 0 THEN WSet, thisWindow 18 | 19 | ; Need to set color decomposition back? 20 | IF (N_Elements(theDecomposedState) NE 0) && (theDepth GT 0) THEN BEGIN 21 | Device, Decomposed=theDecomposedState 22 | ENDIF 23 | RETURN, -1 24 | ENDIF 25 | 26 | ; Go to correct window. 27 | IF not keyword_set(wid) THEN wid =!D.Window 28 | thisWindow = !D.Window 29 | IF (!D.Flags AND 256) NE 0 THEN WSet, wid 30 | 31 | ; Did the user specify a normalized position in the window? 32 | IF keyword_set(position) THEN BEGIN 33 | xstart = position[0] * !D.X_VSize 34 | ystart = position[1] * !D.Y_VSize 35 | ncols = (position[2]*!D.X_VSize) - xstart 36 | nrows = (position[3]*!D.Y_VSize) - ystart 37 | ENDIF 38 | 39 | ; Check keywords and parameters. Define values if necessary. 40 | IF not keyword_set(xstart) THEN xstart = 0 41 | IF not keyword_set(ystart) THEN ystart = 0 42 | IF not keyword_set(ncols) THEN ncols = !D.X_VSize - xstart 43 | IF not keyword_set(nrows) THEN nrows = !D.Y_VSize - ystart 44 | IF not keyword_set(order) THEN order = !Order 45 | IF not keyword_set(true) THEN true = 1 46 | 47 | IF N_Elements(colors) EQ 0 THEN colors = 256 48 | 49 | ; On 24-bit displays, make sure color decomposition is ON. 50 | IF (!D.Flags AND 256) NE 0 THEN BEGIN 51 | Device, Get_Decomposed=theDecomposedState, Get_Visual_Depth=theDepth 52 | IF theDepth GT 8 THEN BEGIN 53 | Device, Decomposed=1 54 | IF theDepth EQ 24 THEN truecolor = true ELSE truecolor = 0 55 | ENDIF ELSE truecolor = 0 56 | IF wid LT 0 THEN BEGIN 57 | Message, 'No currently open windows. Returning.', /NoName 58 | return, -1 59 | ENDIF 60 | ENDIF ELSE BEGIN 61 | truecolor = 0 62 | theDepth = 8 63 | ENDELSE 64 | 65 | ; Fix for 24-bit Z-buffer. 66 | IF (Float(!Version.Release) GE 6.4) AND (!D.NAME EQ 'Z') THEN BEGIN 67 | Device, Get_Decomposed=theDecomposedState, Get_Pixel_Depth=theDepth 68 | IF theDepth EQ 24 THEN truecolor = true ELSE truecolor = 0 69 | ENDIF 70 | 71 | ; Get the screen dump. 2D image on 8-bit displays. 3D image on 24-bit displays. 72 | image = TVRD(xstart,ystart,ncols,nrows,True=truecolor, Order=order) 73 | 74 | ; Need to set color decomposition back? 75 | IF theDepth GT 8 THEN Device, Decomposed=theDecomposedState 76 | 77 | IF truecolor THEN BEGIN 78 | Write_PNG, filename, image, _Extra=extra 79 | ENDIF ELSE BEGIN 80 | TVLCT, r, g, b, /Get 81 | image2D = image 82 | Write_PNG, filename, image2D, r, g, b, _Extra=extra 83 | ENDELSE 84 | 85 | END 86 | --------------------------------------------------------------------------------