source: trunk/GSASIIpath.py @ 3518

Last change on this file since 3518 was 3518, checked in by toby, 3 years ago

proxy/binary load fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 33.4 KB
Line 
1# -*- coding: utf-8 -*-
2'''
3*GSASIIpath: locations & updates*
4---------------------------------
5
6Routines for dealing with file locations, etc.
7
8Determines the location of the compiled (.pyd or .so) libraries.
9
10Interfaces with subversion (svn):
11Determine the subversion release number by determining the highest version number
12where :func:`SetVersionNumber` is called (best done in every GSASII file).
13Other routines will update GSASII from the subversion server if svn can be
14found.
15
16Accesses configuration options, as defined in config.py
17'''
18
19from __future__ import division, print_function
20import os
21import sys
22import platform
23import glob
24import subprocess
25import numpy as np
26g2home = 'https://subversion.xray.aps.anl.gov/pyGSAS'
27'Define the location of the GSAS-II subversion repository'
28   
29path2GSAS2 = os.path.dirname(os.path.abspath(os.path.expanduser(__file__))) # location of this file; save before any changes in pwd
30
31# convert version numbers as '1.2.3' to integers (1002) and back (to 1.2)
32fmtver = lambda v: str(v//1000)+'.'+str(v%1000)
33intver = lambda vs: sum([int(i) for i in vs.split('.')[0:2]]*np.array((1000,1)))
34
35def GetConfigValue(key,default=None):
36    '''Return the configuration file value for key or a default value if not present
37   
38    :param str key: a value to be found in the configuration (config.py) file
39    :param default: a value to be supplied is none is in the config file or
40      the config file is not found. Defaults to None
41    :returns: the value found or the default.
42    '''
43    try:
44        return configDict.get(key,default)
45    except NameError: # this happens when building docs
46        return None
47
48def SetConfigValue(parmdict):
49    '''Set configuration variables from a dictionary where elements are lists
50    First item in list is the default value and second is the value to use.
51    '''
52    global configDict
53    for var in parmdict:
54        if var in configDict:
55            del configDict[var]
56        if isinstance(parmdict[var],tuple):
57            configDict[var] = parmdict[var]
58        else:
59            if parmdict[var][1] is None: continue
60            if parmdict[var][1] == '': continue
61            if parmdict[var][0] == parmdict[var][1]: continue
62            configDict[var] = parmdict[var][1]
63
64# routines for looking a version numbers in files
65version = -1
66def SetVersionNumber(RevString):
67    '''Set the subversion version number
68
69    :param str RevString: something like "$Revision: 3518 $"
70      that is set by subversion when the file is retrieved from subversion.
71
72    Place ``GSASIIpath.SetVersionNumber("$Revision: 3518 $")`` in every python
73    file.
74    '''
75    try:
76        RevVersion = int(RevString.split(':')[1].split()[0])
77        global version
78        version = max(version,RevVersion)
79    except:
80        pass
81       
82def GetVersionNumber():
83    '''Return the maximum version number seen in :func:`SetVersionNumber`
84    '''
85    if version > 1000:
86        return version
87    else:
88        return "unknown"
89
90def LoadConfigFile(filename):
91    '''Read a GSAS-II configuration file.
92    Comments (starting with "%") are removed, as are empty lines
93   
94    :param str filename: base file name (such as 'file.dat'). Files with this name
95      are located from the path and the contents of each are concatenated.
96    :returns: a list containing each non-empty (after removal of comments) line
97      found in every matching config file.
98    '''
99    info = []
100    for path in sys.path:
101        fil = os.path.join(path,filename)
102        if not os.path.exists(fil): continue
103        try:
104            i = 0
105            fp = open(fil,'r')
106            for line in fp:
107                expr = line.split('#')[0].strip()
108                if expr:
109                    info.append(expr)
110                    i += 1
111            print(str(i)+' lines read from config file '+fil)
112        finally:
113            fp.close()
114    return info
115
116
117# routines to interface with subversion
118proxycmds = []
119'Used to hold proxy information for subversion, set if needed in whichsvn'
120svnLocCache = None
121'Cached location of svn to avoid multiple searches for it'
122
123def MakeByte2str(arg):
124    '''Convert output from subprocess pipes (bytes) to str (unicode) in Python 3.
125    In Python 2: Leaves output alone (already str).
126    Leaves stuff of other types alone (including unicode in Py2)
127    Works recursively for string-like stuff in nested loops and tuples.
128
129    typical use::
130
131        out = MakeByte2str(out)
132
133    or::
134
135        out,err = MakeByte2str(s.communicate())
136   
137    '''
138    if isinstance(arg,str): return arg
139    if isinstance(arg,bytes): return arg.decode()
140    if isinstance(arg,list):
141        return [MakeByte2str(i) for i in arg]
142    if isinstance(arg,tuple):
143        return tuple([MakeByte2str(i) for i in arg])
144    return arg
145               
146def getsvnProxy():
147    '''Loads a proxy for subversion from the file created by bootstrap.py
148    '''
149    proxyinfo = os.path.join(path2GSAS2,"proxyinfo.txt")
150    if os.path.exists(proxyinfo):
151        global proxycmds
152        proxycmds = []
153        fp = open(proxyinfo,'r')
154        host = fp.readline().strip()
155        port = fp.readline().strip()
156        fp.close()
157        setsvnProxy(host,port)
158        if not host.strip(): return '',''
159        return host,port
160    return '',''
161
162def setsvnProxy(host,port):
163    '''Sets the svn commands needed to use a proxy
164    '''
165    global proxycmds
166    proxycmds = []
167    host = host.strip()
168    port = port.strip()
169    if not host: return
170    proxycmds.append('--config-option')
171    proxycmds.append('servers:global:http-proxy-host='+host)
172    if port:
173        proxycmds.append('--config-option')
174        proxycmds.append('servers:global:http-proxy-port='+port)
175       
176def whichsvn():
177    '''Returns a path to the subversion exe file, if any is found.
178    Searches the current path after adding likely places where GSAS-II
179    might install svn.
180
181    :returns: None if svn is not found or an absolute path to the subversion
182      executable file.
183    '''
184    # use a previosuly cached svn location
185    global svnLocCache
186    if svnLocCache: return svnLocCache
187    # prepare to find svn
188    is_exe = lambda fpath: os.path.isfile(fpath) and os.access(fpath, os.X_OK)
189    svnprog = 'svn'
190    if sys.platform.startswith('win'): svnprog += '.exe'
191    host,port = getsvnProxy()
192    if GetConfigValue('debug') and host:
193        print('DBG_Using proxy host {} port {}'.format(host,port))
194    # add likely places to find subversion when installed with GSAS-II
195    pathlist = os.environ["PATH"].split(os.pathsep)
196    pathlist.insert(0,os.path.split(sys.executable)[0])
197    pathlist.insert(1,path2GSAS2)
198    for rpt in ('..','bin'),('..','Library','bin'),('svn','bin'),('svn',),('.'):
199        pt = os.path.normpath(os.path.join(path2GSAS2,*rpt))
200        if os.path.exists(pt):
201            pathlist.insert(0,pt)   
202    # search path for svn or svn.exe
203    for path in pathlist:
204        exe_file = os.path.join(path, svnprog)
205        if is_exe(exe_file):
206            try:
207                p = subprocess.Popen([exe_file,'help'],stdout=subprocess.PIPE)
208                res = p.stdout.read()
209                p.communicate()
210                svnLocCache = os.path.abspath(exe_file)
211                return svnLocCache
212            except:
213                pass       
214    svnLocCache = None
215
216def svnVersion(svn=None):
217    '''Get the version number of the current subversion executable
218
219    :returns: a string with a version number such as "1.6.6" or None if
220      subversion is not found.
221
222    '''
223    if not svn: svn = whichsvn()
224    if not svn: return
225
226    cmd = [svn,'--version','--quiet']
227    s = subprocess.Popen(cmd,
228                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
229    out,err = MakeByte2str(s.communicate())
230    if err:
231        print ('subversion error!\nout=%s'%out)
232        print ('err=%s'%err)
233        s = '\nsvn command:  '
234        for i in cmd: s += i + ' '
235        print(s)
236        return None
237    return out.strip()
238
239def svnVersionNumber(svn=None):
240    '''Get the version number of the current subversion executable
241
242    :returns: a fractional version number such as 1.6 or None if
243      subversion is not found.
244
245    '''
246    ver = svnVersion(svn)
247    if not ver: return 
248    M,m = ver.split('.')[:2]
249    return int(M)+int(m)/10.
250
251def svnGetLog(fpath=os.path.split(__file__)[0],version=None):
252    '''Get the revision log information for a specific version of the specified package
253
254    :param str fpath: path to repository dictionary, defaults to directory where
255       the current file is located.
256    :param int version: the version number to be looked up or None (default)
257       for the latest version.
258
259    :returns: a dictionary with keys (one hopes) 'author', 'date', 'msg', and 'revision'
260
261    '''
262    import xml.etree.ElementTree as ET
263    svn = whichsvn()
264    if not svn: return
265    if version is not None:
266        vstr = '-r'+str(version)
267    else:
268        vstr = '-rHEAD'
269
270    cmd = [svn,'log',fpath,'--xml',vstr]
271    if proxycmds: cmd += proxycmds
272    s = subprocess.Popen(cmd,
273                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
274    out,err = MakeByte2str(s.communicate())
275    if err:
276        print ('out=%s'%out)
277        print ('err=%s'%err)
278        s = '\nsvn command:  '
279        for i in cmd: s += i + ' '
280        print(s)
281        return None
282    x = ET.fromstring(out)
283    d = {}
284    for i in x.iter('logentry'):
285        d = {'revision':i.attrib.get('revision','?')}
286        for j in i:
287            d[j.tag] = j.text
288        break # only need the first
289    return d
290
291svnLastError = ''
292def svnGetRev(fpath=os.path.split(__file__)[0],local=True):
293    '''Obtain the version number for the either the last update of the local version
294    or contacts the subversion server to get the latest update version (# of Head).
295
296    :param str fpath: path to repository dictionary, defaults to directory where
297       the current file is located
298    :param bool local: determines the type of version number, where
299       True (default): returns the latest installed update
300       False: returns the version number of Head on the server
301
302    :Returns: the version number as an str or
303       None if there is a subversion error (likely because the path is
304       not a repository or svn is not found). The error message is placed in
305       global variable svnLastError
306    '''
307
308    import xml.etree.ElementTree as ET
309    svn = whichsvn()
310    if not svn: return
311    if local:
312        cmd = [svn,'info',fpath,'--xml']
313    else:
314        cmd = [svn,'info',fpath,'--xml','-rHEAD']
315    if svnVersionNumber() >= 1.6:
316        cmd += ['--non-interactive', '--trust-server-cert']
317    if proxycmds: cmd += proxycmds
318    s = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
319    out,err = MakeByte2str(s.communicate())
320    if err:
321        print ('svn failed\n%s'%out)
322        print ('err=%s'%err)
323        s = '\nsvn command:  '
324        for i in cmd: s += i + ' '
325        print(s)
326        global svnLastError
327        svnLastError = err
328        return None
329    x = ET.fromstring(out)
330    for i in x.iter('entry'):
331        rev = i.attrib.get('revision')
332        if rev: return rev
333
334def svnFindLocalChanges(fpath=os.path.split(__file__)[0]):
335    '''Returns a list of files that were changed locally. If no files are changed,
336       the list has length 0
337
338    :param fpath: path to repository dictionary, defaults to directory where
339       the current file is located
340
341    :returns: None if there is a subversion error (likely because the path is
342       not a repository or svn is not found)
343
344    '''
345    import xml.etree.ElementTree as ET
346    svn = whichsvn()
347    if not svn: return
348    cmd = [svn,'status',fpath,'--xml']
349    if proxycmds: cmd += proxycmds
350    s = subprocess.Popen(cmd,
351                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
352    out,err = MakeByte2str(s.communicate())
353    if err: return None
354    x = ET.fromstring(out)
355    changed = []
356    for i in x.iter('entry'):
357        if i.find('wc-status').attrib.get('item') == 'modified': 
358            changed.append(i.attrib.get('path'))
359    return changed
360
361def svnUpdateDir(fpath=os.path.split(__file__)[0],version=None,verbose=True):
362    '''This performs an update of the files in a local directory from a server.
363
364    :param str fpath: path to repository dictionary, defaults to directory where
365       the current file is located
366    :param version: the number of the version to be loaded. Used only
367       cast as a string, but should be an integer or something that corresponds to a
368       string representation of an integer value when cast. A value of None (default)
369       causes the latest version on the server to be used.
370    '''
371    svn = whichsvn()
372    if not svn: return
373    if version:
374        verstr = '-r' + str(version)
375    else:
376        verstr = '-rHEAD'
377    if verbose: print(u"Updating files at "+fpath)
378    cmd = [svn,'update',fpath,verstr,
379           '--non-interactive',
380           '--accept','theirs-conflict','--force']
381    if svnVersionNumber() >= 1.6:
382        cmd += ['--trust-server-cert']
383    if proxycmds: cmd += proxycmds
384    if verbose:
385        s = 'subversion command:\n  '
386        for i in cmd: s += i + ' '
387        print(s)
388    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
389    out,err = MakeByte2str(s.communicate())
390    if err:
391        print(60*"=")
392        print("****** An error was noted, see below *********")
393        print(60*"=")
394        print(err)
395        s = '\nsvn command:  '
396        for i in cmd: s += i + ' '
397        print(s)
398        sys.exit()
399    elif verbose:
400        print(out)
401
402def svnUpgrade(fpath=os.path.split(__file__)[0]):
403    '''This reformats subversion files, which may be needed if an upgrade of subversion is
404    done.
405
406    :param str fpath: path to repository dictionary, defaults to directory where
407       the current file is located
408    '''
409    svn = whichsvn()
410    if not svn: return
411    cmd = [svn,'upgrade',fpath,'--non-interactive']
412    if proxycmds: cmd += proxycmds
413    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
414    out,err = MakeByte2str(s.communicate())
415    if err:
416        print("svn upgrade did not happen (this is probably OK). Messages:")
417        print (err)
418        s = '\nsvn command:  '
419        for i in cmd: s += i + ' '
420        print(s)
421
422def svnUpdateProcess(version=None,projectfile=None,branch=None):
423    '''perform an update of GSAS-II in a separate python process'''
424    if not projectfile:
425        projectfile = ''
426    else:
427        projectfile = os.path.realpath(projectfile)
428        print ('restart using %s'%projectfile)
429    if branch:
430        version = branch
431    elif not version:
432        version = ''
433    else:
434        version = str(version)
435    # start the upgrade in a separate interpreter (avoids loading .pyd files)
436    subprocess.Popen([sys.executable,__file__,projectfile,version])
437    sys.exit()
438
439def svnSwitchDir(rpath,filename,baseURL,loadpath=None,verbose=True):
440    '''This performs a switch command to move files between subversion trees.
441    Note that if the files were previously downloaded,
442    the switch command will update the files to the newest version.
443   
444    :param str rpath: path to locate files, relative to the GSAS-II
445      installation path (defaults to path2GSAS2)
446    :param str URL: the repository URL
447    :param str loadpath: the prefix for the path, if specified. Defaults to path2GSAS2
448    :param bool verbose: if True (default) diagnostics are printed
449    '''
450    svn = whichsvn()
451    if not svn: return
452    URL = baseURL[:]
453    if baseURL[-1] != '/':
454        URL = baseURL + '/' + filename
455    else:
456        URL = baseURL + filename
457    if loadpath:
458        fpath = os.path.join(loadpath,rpath,filename)
459    else:
460        fpath = os.path.join(path2GSAS2,rpath,filename)
461    cmd = [svn,'switch',URL,fpath,
462           '--non-interactive','--trust-server-cert',
463           '--accept','theirs-conflict','--force']
464    if svnVersionNumber(svn) > 1.6: cmd += ['--ignore-ancestry']
465    if proxycmds: cmd += proxycmds
466    if verbose: print(u"Loading files to "+fpath+u"\n  from "+URL)
467    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
468    out,err = MakeByte2str(s.communicate())
469    if err:
470        print(60*"=")
471        print ("****** An error was noted, see below *********")
472        print(60*"=")
473        print ('out=%s'%out)
474        print ('err=%s'%err)
475        s = '\nsvn command:  '
476        for i in cmd: s += i + ' '
477        print(s)
478        return False
479    if verbose:
480        print('=== Output from svn switch'+(43*'='))
481        print(out.strip())
482        print((70*'=')+'\n')
483    return True
484
485def svnInstallDir(URL,loadpath):
486    '''Load a subversion tree into a specified directory
487
488    :param str URL: the repository URL
489    :param str loadpath: path to locate files
490
491    '''
492    svn = whichsvn()
493    if not svn: return
494    cmd = [svn,'co',URL,loadpath,'--non-interactive']
495    if svnVersionNumber() >= 1.6: cmd += ['--trust-server-cert']
496    print("Loading files from "+URL)
497    if proxycmds: cmd += proxycmds
498    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
499    out,err = MakeByte2str(s.communicate())   #this fails too easily
500    if err:
501        print(60*"=")
502        print ("****** An error was noted, see below *********")
503        print(60*"=")
504        print (err)
505        s = '\nsvn command:  '
506        for i in cmd: s += i + ' '
507        print(s)
508
509        return False
510    print ("Files installed at: "+loadpath)
511    return True
512
513def GetBinaryPrefix():
514    if sys.platform == "win32":
515        prefix = 'win'
516    elif sys.platform == "darwin":
517        prefix = 'mac'
518    elif sys.platform.startswith("linux"):
519        prefix = 'linux'
520    else:
521        print(u'Unknown platform: '+sys.platform)
522        raise Exception('Unknown platform')
523    if platform.architecture()[0] == '64bit':
524        bits = '64'
525    else:
526        bits = '32'
527
528    # format current python version
529    pyver = 'p{}.{}'.format(*sys.version_info[0:2])
530
531    items = [prefix,bits,pyver]
532    return '_'.join(items)
533
534def svnList(URL,verbose=True):
535    '''Get a list of subdirectories from and svn repository
536    '''   
537    svn = whichsvn()
538    if not svn:
539        print('**** unable to load files: svn not found ****')
540        return ''
541    # get binaries matching the required type -- other than for the numpy version
542    cmd = [svn, 'list', URL,'--non-interactive', '--trust-server-cert']
543    if proxycmds: cmd += proxycmds
544    if verbose:
545        s = 'Running svn command:\n  '
546        for i in cmd: s += i + ' '
547        print(s)
548    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
549    res,err = MakeByte2str(p.communicate())
550    return res
551
552def DownloadG2Binaries(g2home,verbose=True):
553    '''Download GSAS-II binaries from appropriate section of the
554    GSAS-II svn repository based on the platform, numpy and Python
555    version
556    '''   
557    bindir = GetBinaryPrefix()
558    #npver = 'n{}.{}'.format(*np.__version__.split('.')[0:2])
559    inpver = intver(np.__version__)
560    svn = whichsvn()
561    if not svn:
562        print('**** unable to load files: svn not found ****')
563        return ''
564    # get binaries matching the required type -- other than for the numpy version
565    cmd = [svn, 'list', g2home + '/Binaries/','--non-interactive', '--trust-server-cert']
566    if proxycmds: cmd += proxycmds
567    if verbose:
568        s = 'Running svn command:\n  '
569        for i in cmd: s += i + ' '
570        print(s)
571    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
572    res,err = MakeByte2str(p.communicate())
573    versions = {}
574    for d in res.split():
575        if d.startswith(bindir):
576            v = intver(d.rstrip('/').split('_')[3].lstrip('n'))
577            versions[v] = d
578    intVersionsList = sorted(versions.keys())
579    if not intVersionsList:
580        print('No binaries located matching',bindir)
581        return
582    elif inpver < min(intVersionsList):
583        vsel = min(intVersionsList)
584        print('Warning: The current numpy version, {}, is older than\n\tthe oldest dist version, {}'
585              .format(np.__version__,fmtver(vsel)))
586    elif inpver >= max(intVersionsList):
587        vsel = max(intVersionsList)
588        if verbose: print(
589                'FYI: The current numpy version, {}, is newer than the newest dist version {}'
590                .format(np.__version__,fmtver(vsel)))
591    else:
592        vsel = min(intVersionsList)
593        for v in intVersionsList:
594            if v <= inpver:
595                vsel = v
596            else:
597                if verbose: print(
598                        'FYI: Selecting dist version {} as the current numpy version, {},\n\tis older than the next dist version {}'
599                        .format(fmtver(vsel),np.__version__,fmtver(v)))
600                break
601    distdir = g2home + '/Binaries/' + versions[vsel]
602    # switch reset command: distdir = g2home + '/trunk/bindist'
603    svnSwitchDir('bindist','',distdir,verbose=verbose)
604    return os.path.join(path2GSAS2,'bindist')
605
606# def svnTestBranch(loc=None):
607#     '''Returns the name of the branch directory if the installation has been switched.
608#     Returns none, if not a branch
609#     the test 2frame branch. False otherwise
610#     '''
611#     if loc is None: loc = path2GSAS2
612#     svn = whichsvn()
613#     if not svn:
614#         print('**** unable to load files: svn not found ****')
615#         return ''
616#     cmd = [svn, 'info', loc]
617#     if proxycmds: cmd += proxycmds
618#     p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
619#     res,err = MakeByte2str(p.communicate())
620#     for l in res.split('\n'):
621#         if "Relative URL:" in l: break
622#     if "/branch/" in l:
623#         return l[l.find("/branch/")+8:].strip()
624#     else:
625#         return None
626   
627def svnSwitch2branch(branch=None,loc=None,svnHome=None):
628    '''Switch to a subversion branch if specified. Switches to trunk otherwise.
629    '''
630    if svnHome is None: svnHome = g2home
631    svnURL = svnHome + '/trunk'
632    if branch:
633        if svnHome.endswith('/'):
634            svnURL = svnHome[:-1]
635        else:
636            svnURL = svnHome
637        if branch.startswith('/'):
638            svnURL += branch
639        else:
640            svnURL += '/' + branch
641    svnSwitchDir('','',svnURL,loadpath=loc)
642   
643
644def IPyBreak_base(userMsg=None):
645    '''A routine that invokes an IPython session at the calling location
646    This routine is only used when debug=True is set in config.py
647    '''
648    savehook = sys.excepthook # save the exception hook
649    try: 
650        from IPython.terminal.embed import InteractiveShellEmbed
651    except ImportError:
652        try:
653            # try the IPython 0.12 approach
654            from IPython.frontend.terminal.embed import InteractiveShellEmbed
655        except ImportError:
656            print ('IPython InteractiveShellEmbed not found')
657            return
658    import inspect
659    ipshell = InteractiveShellEmbed()
660
661    frame = inspect.currentframe().f_back
662    msg   = 'Entering IPython console inside {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
663    if userMsg: msg += userMsg
664    ipshell(msg,stack_depth=2) # Go up one level, to see the calling routine
665    sys.excepthook = savehook # reset IPython's change to the exception hook
666
667try:
668    from IPython.core import ultratb
669except:
670    pass
671def exceptHook(*args):
672    '''A routine to be called when an exception occurs. It prints the traceback
673    with fancy formatting and then calls an IPython shell with the environment
674    of the exception location.
675   
676    This routine is only used when debug=True is set in config.py   
677    '''
678    import IPython.core
679    if sys.platform.startswith('win'):
680        IPython.core.ultratb.FormattedTB(call_pdb=False,color_scheme='NoColor')(*args)
681    else:
682        IPython.core.ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args)
683
684    try: 
685        from IPython.terminal.embed import InteractiveShellEmbed
686    except ImportError:
687        try:
688            # try the IPython 0.12 approach
689            from IPython.frontend.terminal.embed import InteractiveShellEmbed
690        except ImportError:
691            print ('IPython InteractiveShellEmbed not found')
692            return
693    import inspect
694    frame = inspect.getinnerframes(args[2])[-1][0]
695    msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
696    savehook = sys.excepthook # save the exception hook
697    try:
698        InteractiveShellEmbed(banner1=msg)(local_ns=frame.f_locals,global_ns=frame.f_globals)
699    except: # use a different call for IPython 5
700        class c(object): pass
701        pseudomod = c() # create something that acts like a module
702        pseudomod.__dict__ = frame.f_locals
703        InteractiveShellEmbed(banner1=msg)(module=pseudomod,global_ns=frame.f_globals)
704    sys.excepthook = savehook # reset IPython's change to the exception hook
705
706def DoNothing():
707    '''A routine that does nothing. This is called in place of IPyBreak and pdbBreak
708    except when the debug option is set True in config.py
709    '''
710    pass 
711
712IPyBreak = DoNothing
713pdbBreak = DoNothing
714def InvokeDebugOpts():
715    'Called in GSASII.py to set up debug options'
716    if GetConfigValue('debug'):
717        print ('Debug on: IPython: Exceptions and G2path.IPyBreak(); pdb: G2path.pdbBreak()')
718        sys.excepthook = exceptHook
719        import pdb
720        global pdbBreak
721        pdbBreak = pdb.set_trace
722        global IPyBreak
723        IPyBreak = IPyBreak_base
724
725def TestSPG(fpth):
726    '''Test if pyspg.[so,.pyd] can be run from a location in the path
727    '''
728    if not os.path.exists(fpth): return False
729    if not glob.glob(os.path.join(fpth,'pyspg.*')): return False
730    savpath = sys.path[:]
731    sys.path = [fpth]
732    # test to see if a shared library can be used
733    try:
734        import pyspg
735        pyspg.sgforpy('P -1')
736    except Exception as err:
737        print(70*'=')
738        print('Failed to run pyspg in {}\nerror: {}'.format(fpth,err))
739        print(70*'=')
740        sys.path = savpath
741        return False
742    sys.path = savpath
743    return True
744   
745# see if a directory for local modifications is defined. If so, stick that in the path
746if os.path.exists(os.path.expanduser('~/.G2local/')):
747    sys.path.insert(0,os.path.expanduser('~/.G2local/'))
748    fl = glob.glob(os.path.expanduser('~/.G2local/GSASII*.py*'))
749    files = ""
750    prev = None
751    for f in sorted(fl): # make a list of files, dropping .pyc files where a .py exists
752        f = os.path.split(f)[1]
753        if os.path.splitext(f)[0] == prev: continue
754        prev = os.path.splitext(f)[0]
755        if files: files += ", "
756        files += f
757    if files:
758        print("*"*75)
759        print("Warning: the following source files are locally overridden in "+os.path.expanduser('~/.G2local/'))
760        print("  "+files)
761        print("*"*75)
762
763BinaryPathLoaded = False
764def SetBinaryPath(printInfo=False):
765    '''
766    Add location of GSAS-II shared libraries (binaries: .so or .pyd files) to path
767   
768    This routine must be executed after GSASIIpath is imported and before any other
769    GSAS-II imports are done.
770    '''
771    # do this only once no matter how many times it is called
772    global BinaryPathLoaded
773    if BinaryPathLoaded: return
774    try:
775        inpver = intver(np.__version__)
776    except AttributeError: # happens on building docs
777        return
778    binpath = None
779    binprfx = GetBinaryPrefix()
780    for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
781        # Look at bin directory (created by a local compile) before looking for standard dist files
782        searchpathlist = [os.path.join(loc,'bin')]
783        # also look for matching binary dist in loc/AllBinaries
784        versions = {}
785        for d in glob.glob(os.path.join(loc,'AllBinaries',binprfx+'*')):
786            v = intver(d.rstrip('/').split('_')[3].lstrip('n'))
787            versions[v] = d
788        searchpathlist = [os.path.join(loc,'bin')]
789        vmin = None
790        vmax = None
791        for v in sorted(versions.keys()):
792            if v <= inpver:
793                vmin = v
794            elif v > inpver:
795                vmax = v
796                break
797        if vmin in versions:
798            searchpathlist.append(versions[vmin])
799        if vmax in versions:
800            searchpathlist.append(versions[vmax])
801        searchpathlist.append(os.path.join(loc,'bindist'))
802        for fpth in searchpathlist:
803            if TestSPG(fpth):
804                binpath = fpth
805                break       
806        if binpath: break
807    if binpath:                                            # were GSAS-II binaries found
808        sys.path.insert(0,binpath)
809        if printInfo:
810            print('GSAS-II binary directory: {}'.format(binpath))
811        BinaryPathLoaded = True
812    else:                                                  # try loading them
813        if printInfo:
814            print('Attempting to download GSAS-II binary files...')
815        try:
816            binpath = DownloadG2Binaries(g2home)
817        except AttributeError:   # this happens when building in Read The Docs
818            if printInfo:
819                print('Problem with download')
820        if binpath and TestSPG(binpath):
821            if printInfo:
822                print('GSAS-II binary directory: {}'.format(binpath))
823            sys.path.insert(0,binpath)
824            BinaryPathLoaded = True
825        # this must be imported before anything that imports any .pyd/.so file for GSASII
826        else:
827            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
828            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
829            # patch: use old location based on the host OS and the python version, 
830            # path is relative to location of the script that is called as well as this file
831            BinaryPathLoaded = True
832            bindir = None
833            if sys.platform == "win32":
834                if platform.architecture()[0] == '64bit':
835                    bindir = 'binwin64-%d.%d' % sys.version_info[0:2]
836                else:
837                    bindir = 'binwin%d.%d' % sys.version_info[0:2]
838            elif sys.platform == "darwin":
839                if platform.architecture()[0] == '64bit':
840                    bindir = 'binmac64-%d.%d' % sys.version_info[0:2]
841                else:
842                    bindir = 'binmac%d.%d' % sys.version_info[0:2]
843                #if platform.mac_ver()[0].startswith('10.5.'):
844                #    bindir += '_10.5'
845            elif sys.platform.startswith("linux"):
846                if platform.architecture()[0] == '64bit':
847                    bindir = 'binlinux64-%d.%d' % sys.version_info[0:2]
848                else:
849                    bindir = 'binlinux%d.%d' % sys.version_info[0:2]
850            for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
851            # Look at bin directory (created by a local compile) before standard dist
852            # that at the top of the path
853                fpth = os.path.join(loc,bindir)
854                binpath = fpth
855                if TestSPG(fpth):
856                    sys.path.insert(0,binpath)
857                    if printInfo:
858                        print('\n'+75*'*')
859                        print('  Warning. Using an old-style GSAS-II binary library. This is unexpected')
860                        print('  and will break in future GSAS-II versions. Please contact toby@anl.gov')
861                        print('  so we can learn what is not working on your installation.')
862                        print('GSAS-II binary directory: {}'.format(binpath))
863                        print(75*'*')
864                    break
865            else:
866            # end patch
867            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
868            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
869                if printInfo:
870                    print(75*'*')
871                    print('Use of GSAS-II binary directory {} failed!'.format(binpath))
872                    print(75*'*')
873                raise Exception("**** ERROR GSAS-II binary libraries not found, GSAS-II cannot run ****")
874
875    # add the data import and export directory to the search path
876    newpath = os.path.join(path2GSAS2,'imports')
877    if newpath not in sys.path: sys.path.append(newpath)
878    newpath = os.path.join(path2GSAS2,'exports')
879    if newpath not in sys.path: sys.path.append(newpath)
880
881    # setup read of config.py, if present
882    global configDict
883    try:
884        import config
885        configDict = config.__dict__
886        import inspect
887        vals = [True for i in inspect.getmembers(config) if '__' not in i[0]]
888        if printInfo:
889            print (str(len(vals))+' values read from config file '+os.path.abspath(config.__file__))
890    except ImportError:
891        configDict = {'Clip_on':True}
892    except Exception as err:
893        if printInfo:
894            print("Error importing config.py file: "+str(err))
895        configDict = {'Clip_on':True}
896
897if __name__ == '__main__':
898    '''What follows is called to update (or downdate) GSAS-II in a separate process.
899    '''
900    import time
901    time.sleep(1) # delay to give the main process a chance to exit
902    # perform an update and restart GSAS-II
903    project,version = sys.argv[1:3]
904    loc = os.path.dirname(__file__)
905    if version == 'trunk':
906        svnSwitch2branch('')
907    elif '/' in version:
908        svnSwitch2branch(version)
909    elif version:
910        print("Regress to version "+str(version))
911        svnUpdateDir(loc,version=version)
912    else:
913        print("Update to current version")
914        svnUpdateDir(loc)
915    ex = sys.executable
916    if sys.platform == "darwin": # mac requires pythonw which is not always reported as sys.executable
917        if os.path.exists(ex+'w'): ex += 'w'
918    if project:
919        print("Restart GSAS-II with project file "+str(project))
920        subprocess.Popen([ex,os.path.join(loc,'GSASII.py'),project])
921    else:
922        print("Restart GSAS-II without a project file ")
923        subprocess.Popen([ex,os.path.join(loc,'GSASII.py')])
924    print ('exiting update process')
925    sys.exit()
Note: See TracBrowser for help on using the repository browser.