source: trunk/GSASIIpath.py @ 3136

Last change on this file since 3136 was 3136, checked in by vondreele, 5 years ago

make GSAS-II python 3.6 compliant & preserve python 2.7 use;changes:
do from future import division, print_function for all GSAS-II py sources
all menu items revised to be py 2.7/3.6 compliant
all wx.OPEN --> wx.FD_OPEN in file dialogs
all integer divides (typically for image pixel math) made explicit with ; ambiguous ones made floats as appropriate
all print "stuff" --> print (stuff)
all print >> pFile,'stuff' --> pFile.writeCIFtemplate('stuff')
all read file opens made explicit 'r' or 'rb'
all cPickle imports made for py2.7 or 3.6 as cPickle or _pickle; test for '2' platform.version_tuple[0] for py 2.7
define cPickleload to select load(fp) or load(fp,encoding='latin-1') for loading gpx files; provides cross compatibility between py 2.7/3.6 gpx files
make dict.keys() as explicit list(dict.keys()) as needed (NB: possible source of remaining py3.6 bugs)
make zip(a,b) as explicit list(zip(a,b)) as needed (NB: possible source of remaining py3.6 bugs)
select unichr/chr according test for '2' platform.version_tuple[0] for py 2.7 (G2pwdGUI * G2plot) for special characters
select wg.EVT_GRID_CELL_CHANGE (classic) or wg.EVT_GRID_CELL_CHANGED (phoenix) in grid Bind
maxint --> maxsize; used in random number stuff
raise Exception,"stuff" --> raise Exception("stuff")
wx 'classic' sizer.DeleteWindows?() or 'phoenix' sizer.Clear(True)
wx 'classic' SetToolTipString?(text) or 'phoenix' SetToolTip?(wx.ToolTip?(text)); define SetToolTipString?(self,text) to handle the choice in plots
status.SetFields? --> status.SetStatusText?
'classic' AddSimpleTool? or 'phoenix' self.AddTool? for plot toolbar; Bind different as well
define GetItemPydata? as it doesn't exist in wx 'phoenix'
allow python versions 2.7 & 3.6 to run GSAS-II
Bind override commented out - no logging capability (NB: remove all logging code?)
all import ContentsValidator? open filename & test if valid then close; filepointer removed from Reader
binary importers (mostly images) test for 'byte' type & convert as needed to satisfy py 3.6 str/byte rules

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