source: trunk/GSASIIpath.py @ 3246

Last change on this file since 3246 was 3246, checked in by toby, 5 years ago

cif export: use sig for x,x,x positions etc; column order for seq table atom positions; misc Py3 fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 32.1 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: 3246 $"
70      that is set by subversion when the file is retrieved from subversion.
71
72    Place ``GSASIIpath.SetVersionNumber("$Revision: 3246 $")`` 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.insert(0,os.path.split(sys.executable)[0])
172    pathlist.insert(1,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().decode()
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.startswith("linux"):
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.decode().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    # IPyBreak_base() # need fix below for Python3
633    if 'win' in sys.platform:
634        ultratb.FormattedTB(call_pdb=False,color_scheme='NoColor')(*args)
635    else:
636        ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args)
637    try: 
638        from IPython.terminal.embed import InteractiveShellEmbed
639    except ImportError:
640        try:
641            # try the IPython 0.12 approach
642            from IPython.frontend.terminal.embed import InteractiveShellEmbed
643        except ImportError:
644            print ('IPython InteractiveShellEmbed not found')
645            return
646    import inspect
647    frame = inspect.getinnerframes(args[2])[-1][0]
648    msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
649    savehook = sys.excepthook # save the exception hook
650    try:
651        InteractiveShellEmbed(banner1=msg)(local_ns=frame.f_locals,global_ns=frame.f_globals)
652    except: # use a different call for IPython 5
653        class c(object): pass
654        pseudomod = c() # create something that acts like a module
655        pseudomod.__dict__ = frame.f_locals
656        InteractiveShellEmbed(banner1=msg)(module=pseudomod,global_ns=frame.f_globals)
657    sys.excepthook = savehook # reset IPython's change to the exception hook
658
659def DoNothing():
660    '''A routine that does nothing. This is called in place of IPyBreak and pdbBreak
661    except when the debug option is set True in config.py
662    '''
663    pass 
664
665IPyBreak = DoNothing
666pdbBreak = DoNothing
667def InvokeDebugOpts():
668    'Called in GSASII.py to set up debug options'
669    if GetConfigValue('debug'):
670        print ('Debug on: IPython: Exceptions and G2path.IPyBreak(); pdb: G2path.pdbBreak()')
671        sys.excepthook = exceptHook
672        import pdb
673        global pdbBreak
674        pdbBreak = pdb.set_trace
675        global IPyBreak
676        IPyBreak = IPyBreak_base
677
678def TestSPG(fpth):
679    '''Test if pyspg.[so,.pyd] can be run from a location in the path
680    '''
681    if not os.path.exists(fpth): return False
682    if not glob.glob(os.path.join(fpth,'pyspg.*')): return False
683    savpath = sys.path[:]
684    sys.path = [fpth]
685    # test to see if a shared library can be used
686    try:
687        import pyspg
688        pyspg.sgforpy('P -1')
689    except Exception as err:
690        print(70*'=')
691        print('Failed to run pyspg in {}\nerror: {}'.format(fpth,err))
692        print(70*'=')
693        sys.path = savpath
694        return False
695    sys.path = savpath
696    return True
697   
698# see if a directory for local modifications is defined. If so, stick that in the path
699if os.path.exists(os.path.expanduser('~/.G2local/')):
700    sys.path.insert(0,os.path.expanduser('~/.G2local/'))
701    import glob
702    fl = glob.glob(os.path.expanduser('~/.G2local/GSASII*.py*'))
703    files = ""
704    prev = None
705    for f in sorted(fl): # make a list of files, dropping .pyc files where a .py exists
706        f = os.path.split(f)[1]
707        if os.path.splitext(f)[0] == prev: continue
708        prev = os.path.splitext(f)[0]
709        if files: files += ", "
710        files += f
711    if files:
712        print("*"*75)
713        print("Warning: the following source files are locally overridden in "+os.path.expanduser('~/.G2local/'))
714        print("  "+files)
715        print("*"*75)
716
717BinaryPathLoaded = False
718def SetBinaryPath(printInfo=True):
719    '''
720    Add location of GSAS-II shared libraries (binaries: .so or .pyd files) to path
721   
722    This routine must be executed after GSASIIpath is imported and before any other
723    GSAS-II imports are done.
724    '''
725    # do this only once no matter how many times it is called
726    global BinaryPathLoaded
727    if BinaryPathLoaded: return
728    try:
729        inpver = intver(np.__version__)
730    except AttributeError: # happens on building docs
731        return
732    binpath = None
733    binprfx = GetBinaryPrefix()
734    for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
735        # Look at bin directory (created by a local compile) before looking for standard dist files
736        searchpathlist = [os.path.join(loc,'bin')]
737        # also look for matching binary dist in loc/AllBinaries
738        versions = {}
739        for d in glob.glob(os.path.join(loc,'AllBinaries',binprfx+'*')):
740            v = intver(d.rstrip('/').split('_')[3].lstrip('n'))
741            versions[v] = d
742        searchpathlist = [os.path.join(loc,'bin')]
743        vmin = None
744        vmax = None
745        for v in sorted(versions.keys()):
746            if v <= inpver:
747                vmin = v
748            elif v > inpver:
749                vmax = v
750                break
751        if vmin in versions:
752            searchpathlist.append(versions[vmin])
753        if vmax in versions:
754            searchpathlist.append(versions[vmax])
755        searchpathlist.append(os.path.join(loc,'bindist'))
756        for fpth in searchpathlist:
757            if TestSPG(fpth):
758                binpath = fpth
759                break       
760        if binpath: break
761    if binpath:                                            # were GSAS-II binaries found
762        sys.path.insert(0,binpath)
763        if printInfo:
764            print('GSAS-II binary directory: {}'.format(binpath))
765        BinaryPathLoaded = True
766    else:                                                  # try loading them
767        if printInfo:
768            print('Attempting to download GSAS-II binary files...')
769        try:
770            binpath = DownloadG2Binaries(g2home)
771        except AttributeError:   # this happens when building in Read The Docs
772            if printInfo:
773                print('Problem with download')
774        if binpath and TestSPG(binpath):
775            if printInfo:
776                print('GSAS-II binary directory: {}'.format(binpath))
777            sys.path.insert(0,binpath)
778            BinaryPathLoaded = True
779        # this must be imported before anything that imports any .pyd/.so file for GSASII
780        else:
781            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
782            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
783            # patch: use old location based on the host OS and the python version, 
784            # path is relative to location of the script that is called as well as this file
785            BinaryPathLoaded = True
786            bindir = None
787            if sys.platform == "win32":
788                if platform.architecture()[0] == '64bit':
789                    bindir = 'binwin64-%d.%d' % sys.version_info[0:2]
790                else:
791                    bindir = 'binwin%d.%d' % sys.version_info[0:2]
792            elif sys.platform == "darwin":
793                if platform.architecture()[0] == '64bit':
794                    bindir = 'binmac64-%d.%d' % sys.version_info[0:2]
795                else:
796                    bindir = 'binmac%d.%d' % sys.version_info[0:2]
797                #if platform.mac_ver()[0].startswith('10.5.'):
798                #    bindir += '_10.5'
799            elif sys.platform.startswith("linux"):
800                if platform.architecture()[0] == '64bit':
801                    bindir = 'binlinux64-%d.%d' % sys.version_info[0:2]
802                else:
803                    bindir = 'binlinux%d.%d' % sys.version_info[0:2]
804            for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
805            # Look at bin directory (created by a local compile) before standard dist
806            # that at the top of the path
807                fpth = os.path.join(loc,bindir)
808                binpath = fpth
809                if TestSPG(fpth):
810                    sys.path.insert(0,binpath)
811                    if printInfo:
812                        print('\n'+75*'*')
813                        print('  Warning. Using an old-style GSAS-II binary library. This is unexpected')
814                        print('  and will break in future GSAS-II versions. Please contact toby@anl.gov')
815                        print('  so we can learn what is not working on your installation.')
816                        print('GSAS-II binary directory: {}'.format(binpath))
817                        print(75*'*')
818                    break
819            else:
820            # end patch
821            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
822            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
823                if printInfo:
824                    print(75*'*')
825                    print('Use of GSAS-II binary directory {} failed!'.format(binpath))
826                    print(75*'*')
827                raise Exception("**** ERROR GSAS-II binary libraries not found, GSAS-II cannot run ****")
828
829    # add the data import and export directory to the search path
830    newpath = os.path.join(path2GSAS2,'imports')
831    if newpath not in sys.path: sys.path.append(newpath)
832    newpath = os.path.join(path2GSAS2,'exports')
833    if newpath not in sys.path: sys.path.append(newpath)
834
835    # setup read of config.py, if present
836    global configDict
837    try:
838        import config
839        configDict = config.__dict__
840        import inspect
841        vals = [True for i in inspect.getmembers(config) if '__' not in i[0]]
842        if printInfo:
843            print (str(len(vals))+' values read from config file '+os.path.abspath(config.__file__))
844    except ImportError:
845        configDict = {'Clip_on':True}
846    except Exception as err:
847        if printInfo:
848            print("Error importing config.py file: "+str(err))
849        configDict = {'Clip_on':True}
850
851if __name__ == '__main__':
852    '''What follows is called to update (or downdate) GSAS-II in a separate process.
853    '''
854    import time
855    time.sleep(1) # delay to give the main process a chance to exit
856    # perform an update and restart GSAS-II
857    project,version = sys.argv[1:3]
858    loc = os.path.dirname(__file__)
859    if version == 'trunk':
860        svnSwitch2branch('')
861    elif '/' in version:
862        svnSwitch2branch(version)
863    elif version:
864        print("Regress to version "+str(version))
865        svnUpdateDir(loc,version=version)
866    else:
867        print("Update to current version")
868        svnUpdateDir(loc)
869    ex = sys.executable
870    if sys.platform == "darwin": # mac requires pythonw which is not always reported as sys.executable
871        if os.path.exists(ex+'w'): ex += 'w'
872    if project:
873        print("Restart GSAS-II with project file "+str(project))
874        subprocess.Popen([ex,os.path.join(loc,'GSASII.py'),project])
875    else:
876        print("Restart GSAS-II without a project file ")
877        subprocess.Popen([ex,os.path.join(loc,'GSASII.py')])
878    print ('exiting update process')
879    sys.exit()
Note: See TracBrowser for help on using the repository browser.