source: trunk/GSASIIpath.py @ 3513

Last change on this file since 3513 was 3513, checked in by svnjenkins, 3 years ago

more svn diagnostics

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