├── README.md └── setup_casapy_pip.py /README.md: -------------------------------------------------------------------------------- 1 | CASA Python executable wrapper 2 | ============================== 3 | 4 | The approach described below is deprecated. 5 | 6 | Instead, follow instructions here: 7 | https://docs.astropy.org/en/stable/install.html#installing-astropy-into-casa 8 | to install astropy or other packages into CASA. 9 | 10 | About 11 | ----- 12 | 13 | ``casa-python`` is a simple script that allows users to invoke the 14 | Python executable for [CASA](http://casa.nrao.edu/) as one would 15 | invoke a normal Python executable. This allows users to easily install 16 | third-party libraries into CASA. To do this, whenever installation 17 | instructions require you to run for example ``python setup.py install``, 18 | instead use: 19 | 20 | casa-python setup.py install 21 | 22 | We also provide an interface to the ``pip`` package manager, ``casa-pip``. One can install 23 | any\* python package this way: 24 | 25 | casa-pip install requests 26 | 27 | Installation 28 | ------------ 29 | 30 | The installation requires that you have CASA installed. You can check this by doing 31 | 32 | $ which casa 33 | 34 | at the command prompt. You should see the path to the file. 35 | 36 | To install, download the latest version of the ``casa-python`` script from 37 | [here](https://raw.githubusercontent.com/radio-tools/casa-python/master/setup_casapy_pip.py) 38 | and run it. This should be your *system* python, not *CASA* python (which 39 | should be on your path by default). 40 | 41 | python setup_casapy_pip.py 42 | 43 | or, alternatively: 44 | 45 | curl -O https://raw.githubusercontent.com/radio-tools/casa-python/master/setup_casapy_pip.py 46 | python setup_casapy_pip.py 47 | 48 | You should then add `$HOME/.casa/bin/` to your path. 49 | 50 | Example 51 | ------- 52 | 53 | To install Astropy into CASA, assuming you have the appropriate compilers on 54 | your system, you can run 55 | 56 | casa-pip install astropy 57 | 58 | Once the installation has completed, you can start up CASA as usual, and 59 | Astropy should be available: 60 | 61 | CASA Version 4.1.0 (r22971) 62 | Compiled on: Thu 2013/02/21 17:38:25 UTC 63 | ___________________________________________________________________ 64 | For help use the following commands: 65 | tasklist - Task list organized by category 66 | taskhelp - One line summary of available tasks 67 | help taskname - Full help for task 68 | toolhelp - One line summary of available tools 69 | help par.parametername - Full help for parameter name 70 | ___________________________________________________________________ 71 | Activating auto-logging. Current session state plus future input saved. 72 | Filename : ipython-20130319-150704.log 73 | Mode : backup 74 | Output logging : False 75 | Raw input log : False 76 | Timestamping : False 77 | State : active 78 | *** Loading ATNF ASAP Package... 79 | *** ... ASAP (trunk rev#22948) import complete *** 80 | 81 | CASA <2>: import astropy 82 | 83 | CASA <3>: 84 | 85 | 86 | Caveats 87 | ------- 88 | 89 | Packages requiring c-compiled code rely on the existence of a C-compiler on 90 | your unix path. 91 | 92 | Alternatives 93 | ------------ 94 | 95 | Rather than install packages into CASA, it is also possible (although a little hackier) to try and import CASA into your existing Python installation - see [here](http://newton.cx/~peter/2014/02/casa-in-python-without-casapy/) for more details. 96 | 97 | Credits 98 | ------- 99 | 100 | The wrapper was prepared by Thomas Robitaille (@astrofrog) based on code from 101 | CASA, with contributions from Adam Leroy and Adam Ginsburg (@keflavich). 102 | -------------------------------------------------------------------------------- /setup_casapy_pip.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | import errno 5 | import stat 6 | import tempfile 7 | import subprocess 8 | import platform 9 | 10 | from distutils.spawn import find_executable 11 | from hashlib import md5 12 | from urllib import urlopen 13 | 14 | USER_DIR = os.path.join(os.path.expanduser('~'), '.casa') 15 | BIN_DIR = os.path.join(os.path.expanduser('~'), '.casa', 'bin') 16 | USER_SITE = os.path.join(os.path.expanduser('~'), '.casa', 'lib', 'python{pv}', 'site-packages') 17 | 18 | PIP_URL = "https://pypi.python.org/packages/source/p/pip/pip-1.5.4.tar.gz" 19 | PIP_MD5 = "834b2904f92d46aaa333267fb1c922bb" 20 | 21 | SETUPTOOLS_URL = "https://pypi.python.org/packages/source/s/setuptools/setuptools-3.4.3.tar.gz" 22 | SETUPTOOLS_MD5 = "284bf84819c0f6735c853619d1a54955" 23 | 24 | 25 | def mkdir_p(path): 26 | # Create a directory using mkdir -p 27 | # Solution provided on StackOverflow 28 | try: 29 | os.makedirs(path) 30 | except OSError as exc: 31 | if not(exc.errno == errno.EEXIST and os.path.isdir(path)): 32 | raise 33 | 34 | 35 | def make_executable(filename): 36 | st = os.stat(filename) 37 | os.chmod(filename, st.st_mode | stat.S_IEXEC) 38 | 39 | def find_osx_executable(fpath='/Applications/CASA.app/Contents/MacOS/casapy'): 40 | if os.path.isfile(fpath) and os.access(fpath, os.X_OK): 41 | return fpath 42 | 43 | def get_casapy_path(): 44 | casapy_path = find_executable('casapy') or find_osx_executable() 45 | if casapy_path is None: 46 | raise SystemError("Could not locate casapy command") 47 | casapy_path = os.path.realpath(casapy_path) 48 | if not os.path.exists(casapy_path): 49 | raise SystemError("The casapy command does not point to a valid CASA installation") 50 | return casapy_path 51 | 52 | 53 | def get_python_version_mac(): 54 | casapy_path = get_casapy_path() 55 | parent = os.path.dirname(casapy_path) 56 | python = os.path.join(parent, 'python') 57 | p = subprocess.Popen([python, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 58 | p.wait() 59 | version = p.stderr.read().split()[1][:3] 60 | print("Determined Python version in CASA... {0}".format(version)) 61 | return version 62 | 63 | def get_python_path_linux(): 64 | """ get the version and the appropriate parent directory path """ 65 | casapy_path = get_casapy_path() 66 | parent = os.path.dirname(casapy_path) 67 | grandparent = os.path.dirname(parent) 68 | version = None 69 | for lib in ('lib64','lib'): 70 | if os.path.exists(os.path.join(grandparent, lib, 'python2.7')): 71 | version = "2.7" 72 | path = grandparent 73 | elif os.path.exists(os.path.join(grandparent, lib, 'python2.6')): 74 | version = "2.6" 75 | path = grandparent 76 | elif os.path.exists(os.path.join(parent, lib, 'python2.7')): 77 | version = "2.7" 78 | path = parent 79 | elif os.path.exists(os.path.join(parent, lib, 'python2.6')): 80 | version = "2.6" 81 | path = parent 82 | if version is not None: 83 | break 84 | if version is None: 85 | raise ValueError("Could not determine Python version") 86 | return version,path,lib 87 | 88 | def get_python_version_linux(): 89 | version,casapy_parent_path,lib = get_python_path_linux() 90 | print("Determined Python version in CASA... {0}".format(version)) 91 | return version 92 | 93 | 94 | def install_package(pv="2.7",packagename='pip',url=PIP_URL,md5_checksum=PIP_MD5): 95 | 96 | print("Downloading {0}...".format(packagename)) 97 | 98 | # Create temporary directory 99 | 100 | tmpdir = tempfile.mkdtemp() 101 | os.chdir(tmpdir) 102 | 103 | # Download module and expand 104 | 105 | content = urlopen(url).read() 106 | 107 | if md5(content).hexdigest() != md5_checksum: 108 | raise ValueError("checksum does not match") 109 | 110 | with open(os.path.basename(url), 'wb') as f: 111 | f.write(content) 112 | 113 | # Prepare installation script 114 | 115 | print("Installing {0}...".format(packagename)) 116 | 117 | site_packages = os.path.expanduser('~/.casa/lib/python{pv}/site-packages'.format(pv=pv)) 118 | mkdir_p(site_packages) 119 | 120 | PKG_INSTALL = """ 121 | #!/bin/bash 122 | export PYTHONUSERBASE=$HOME/.casa 123 | export PATH=$HOME/.casa/bin:$PATH 124 | tar xvzf {pkg_filename} 125 | cd {pkg_name} 126 | casa-python setup.py install --prefix=$HOME/.casa 127 | """ 128 | 129 | pkg_filename = os.path.basename(url) 130 | pkg_name = pkg_filename.rsplit('.', 2)[0] 131 | 132 | with open('install_pkg.sh', 'w') as f: 133 | f.write(PKG_INSTALL.format(pkg_filename=pkg_filename, pkg_name=pkg_name)) 134 | 135 | make_executable('install_pkg.sh') 136 | 137 | # Need to use subprocess instead 138 | retcode = os.system('./install_pkg.sh') 139 | if retcode != 0: 140 | raise SystemError("{0} installation failed!".format(packagename)) 141 | 142 | 143 | def write_casa_python_mac(pv="2.7"): 144 | 145 | print("Creating casa-python script...") 146 | 147 | TEMPLATE_PYTHON = """ 148 | #!/bin/sh 149 | 150 | INSTALLPATH={casapy_path} 151 | 152 | PROOT=$INSTALLPATH/Frameworks/Python.framework/Versions/{pv} 153 | PBIND=$PROOT/MacOS 154 | PLIBD=$PROOT/lib/python{pv} 155 | PPATH=$PBIND:$PLIBD:$PLIBD/plat-mac:$PLIBD/plat-darwin 156 | PPATH=$PPATH:$PBIND/lib-scriptpackages:$PLIBD/lib-tk 157 | PPATH=$PPATH:$PLIBD/lib-dynload:$PLIBD/site-packages 158 | PPATH=$PPATH:$PLIBD/site-packages/Numeric:$PLIBD/site-packages/PyObjC 159 | PPATH=$INSTALLPATH/Resources/python:$PPATH 160 | 161 | export PYTHONUSERBASE=$HOME/.casa 162 | 163 | export PYTHONHOME=$PROOT 164 | export PYTHONPATH={user_site2}:$PPATH 165 | export PYTHONPATH={user_site}:$PPATH 166 | export PYTHONEXECUTABLE=$PROOT/Resources/Python.app/Contents/MacOS/Python 167 | 168 | export DYLD_FRAMEWORK_PATH="$INSTALLPATH/Frameworks" 169 | 170 | exec -a pythonw $INSTALLPATH/MacOS/pythonw -W ignore::DeprecationWarning "$@" 171 | """ 172 | 173 | mkdir_p(BIN_DIR) 174 | 175 | casapy_path = os.path.dirname(os.path.dirname(get_casapy_path())) 176 | 177 | # On some installs of CASA, the user-site uses a python-version-independent 178 | # site-packages directory, which has something to do with the way USER_SITE 179 | # is set for OSX Frameworks. We therefore add a second directory to the 180 | # path BEHIND the "correct" python version path. 181 | 182 | with open(os.path.join(BIN_DIR, 'casa-python'), 'w') as f: 183 | f.write(TEMPLATE_PYTHON.format(casapy_path=casapy_path, pv=pv, 184 | user_site2=USER_SITE.format(pv=''), 185 | user_site=USER_SITE.format(pv=pv))) 186 | 187 | make_executable(os.path.join(BIN_DIR, 'casa-python')) 188 | 189 | 190 | def write_casa_python_linux(pv="2.7"): 191 | 192 | print("Creating casa-python script...") 193 | 194 | TEMPLATE_PYTHON = """ 195 | #!/bin/sh 196 | 197 | INSTALLPATH={casapy_path} 198 | 199 | export LD_LIBRARY_PATH=$INSTALLPATH/{lib}:/{lib}:/usr/{lib}:$LD_LIBRARY_PATH 200 | export LDFLAGS="-L$INSTALLPATH/{lib}/" 201 | 202 | export PYTHONHOME=$INSTALLPATH 203 | 204 | export PYTHONUSERBASE=$HOME/.casa 205 | 206 | export PYTHONPATH=$INSTALLPATH/{lib}/python{pv}/site-packages:$PYTHONPATH 207 | export PYTHONPATH=$INSTALLPATH/{lib}/python{pv}/heuristics:$PYTHONPATH 208 | export PYTHONPATH=$INSTALLPATH/{lib}/python{pv}:$PYTHONPATH 209 | 210 | exec $INSTALLPATH/{lib}/{lib_casapy}/bin/python $* 211 | """ 212 | 213 | mkdir_p(BIN_DIR) 214 | 215 | # vers is throwaway here 216 | vers,casapy_path,lib = get_python_path_linux() 217 | # parent directory of 'bin' changed from casapy -> casa from 4.2 to 4.3? 218 | lib_casapy = {'lib64':'casapy', 219 | 'lib' : 'casa'} 220 | 221 | with open(os.path.join(BIN_DIR, 'casa-python'), 'w') as f: 222 | f.write(TEMPLATE_PYTHON.format(casapy_path=casapy_path, pv=pv, 223 | lib=lib, lib_casapy=lib_casapy[lib])) 224 | 225 | make_executable(os.path.join(BIN_DIR, 'casa-python')) 226 | 227 | 228 | def write_casa_pip(): 229 | 230 | print("Creating casa-pip script...") 231 | 232 | TEMPLATE_PIP = """ 233 | $HOME/.casa/bin/casa-python $HOME/.casa/bin/pip $* --user 234 | """ 235 | 236 | with open(os.path.join(BIN_DIR, 'casa-pip'), 'w') as f: 237 | f.write(TEMPLATE_PIP) 238 | 239 | make_executable(os.path.join(BIN_DIR, 'casa-pip')) 240 | 241 | 242 | def write_init(pv="2.7"): 243 | 244 | print("Creating init.py script...") 245 | 246 | TEMPLATE_INIT = """ 247 | import site 248 | site.addsitedir("{site_packages}") 249 | site.addsitedir("{site_packages_noversion}") 250 | """ 251 | 252 | with open(os.path.join(USER_DIR, 'init.py'), 'a') as f: 253 | f.write(TEMPLATE_INIT.format(site_packages=USER_SITE.format(pv=pv), 254 | site_packages_noversion=USER_SITE.format(pv=''))) 255 | 256 | 257 | def add_bin_to_path(): 258 | # TODO: make this happne in future 259 | print("You should now add {0} to your PATH".format(BIN_DIR)) 260 | 261 | 262 | if __name__ == "__main__": 263 | 264 | if platform.system() == 'Darwin': 265 | 266 | python_version = get_python_version_mac() 267 | write_casa_python_mac(pv=python_version) 268 | 269 | else: 270 | 271 | python_version = get_python_version_linux() 272 | write_casa_python_linux(pv=python_version) 273 | 274 | 275 | install_package(pv=python_version, packagename='setuptools', 276 | url=SETUPTOOLS_URL, md5_checksum=SETUPTOOLS_MD5) 277 | install_package(pv=python_version, packagename='pip', url=PIP_URL, 278 | md5_checksum=PIP_MD5) 279 | write_casa_pip() 280 | write_init(pv=python_version) 281 | 282 | add_bin_to_path() 283 | --------------------------------------------------------------------------------