@@ -579,173 +579,155 @@ def WriteInstprm(fp, InstPrm, InstPrm1, Sample={}, bank=None):
579579 #write output string
580580 fp .write (resString )
581581
582- # version of LoadImportRoutines from before switch to "main"
583- # def _old_LoadImportRoutines(prefix, errprefix=None, traceback=False):
584- # '''Routine to locate GSASII importers matching a prefix string.
585- #
586- # Warns if more than one file with the same name is in the path
587- # or if a file is found that is not in the main directory tree.
588- # '''
589- # if errprefix is None:
590- # errprefix = prefix
591- #
592- # readerlist = []
593- # import_files = {}
594- # if '.' not in sys.path: sys.path.append('.')
595- # for path in sys.path:
596- # for filename in glob.iglob(os.path.join(path, 'G2'+prefix+'*.py')):
597- # pkg = os.path.splitext(os.path.split(filename)[1])[0]
598- # if pkg in import_files:
599- # G2Print('Warning: importer {} overrides {}'.format(import_files[pkg],os.path.abspath(filename)))
600- # elif not filename.startswith(GSASIIpath.path2GSAS2):
601- # G2Print('Note: found importer in non-standard location:'+
602- # f'\n\t{os.path.abspath(filename)}')
603- # import_files[pkg] = filename
604- # else:
605- # import_files[pkg] = filename
606-
607- # for pkg in sorted(import_files.keys()):
608- # try:
609- # exec('import '+pkg)
610- # #print(eval(pkg+'.__file__'))
611- # for name, value in inspect.getmembers(eval(pkg)):
612- # if name.startswith('_'):
613- # continue
614- # if inspect.isclass(value):
615- # for method in 'Reader', 'ExtensionValidator', 'ContentsValidator':
616- # if not hasattr(value, method):
617- # break
618- # if not callable(getattr(value, method)):
619- # break
620- # else:
621- # reader = value()
622- # if reader.UseReader:
623- # readerlist.append(reader)
624- # except AttributeError:
625- # G2Print ('Import_' + errprefix + ': Attribute Error ' + import_files[pkg])
626- # if traceback:
627- # traceback.print_exc(file=sys.stdout)
628- # except Exception as exc:
629- # G2Print ('\nImport_' + errprefix + ': Error importing file ' + import_files[pkg])
630- # G2Print (u'Error message: {}\n'.format(exc))
631- # if traceback:
632- # traceback.print_exc(file=sys.stdout)
633- # return readerlist
634-
635582def LoadImportRoutines (prefix , errprefix = None , traceback = False ):
583+ '''Loads import routines from the GSASII.imports area and
584+ from a user-supplied area, ~/.GSASII/imports.
585+
586+ :param str prefix: string used in the file name to differentiate the
587+ importer type (e.g. `G2img_xyz.py` is an importer for images. Will
588+ be one of 'img' (images), 'pdf' (pair distribution function),
589+ 'phase' (cell/coordinates), 'pwd' (powder diffraction), 'rfd'
590+ (reflectivity), 'sad' (small-angle scattering) or 'sfact'
591+ (single crystal).
592+ :param errprefix: no longer used
593+ :param traceback: no longer used
594+ :returns: a list of reader routines (callable objects)
595+ '''
636596 from . import imports
637597 readerlist = []
638- # how to import directly from a file for extra search magic if we need
639- # https://stackoverflow.com/questions/67631/how-can-i-import-a-module-dynamically-given-the-full-path
640- # TODO handle non-bundled readers
598+ # configure readers that have already been imported
641599 for mod_name in (_ for _ in dir (imports ) if _ .startswith (f'G2{ prefix } ' )):
642600 mod = getattr (imports , mod_name )
643601 for member_name in dir (mod ):
644602 if member_name .startswith ('_' ):
645603 continue
646604 member = getattr (mod , member_name )
647- if all (
648- hasattr ( member , meth )
649- for meth in ( 'Reader' , 'ExtensionValidator' , 'ContentsValidator' )
650- ) :
605+ if not callable ( member ): continue
606+ for meth in ( 'Reader' , 'ExtensionValidator' , 'ContentsValidator' , 'UseReader' ):
607+ if not hasattr ( member , meth ): break
608+ else :
651609 reader = member ()
652610 if reader .UseReader :
653611 readerlist .append (reader )
612+ # Now look for modules in the "user-defined" area (~/.GSASII/imports)
613+ fnam = os .path .expanduser (os .path .normpath (f'~/.GSASII/imports/G2{ prefix } *.py' ))
614+ import importlib .util
615+ for f in sorted (glob .glob (fnam )):
616+ nam = os .path .splitext (os .path .split (f )[1 ])[0 ]
617+ try :
618+ modspec = importlib .util .spec_from_file_location (nam , f )
619+ module = importlib .util .module_from_spec (modspec )
620+ # will process "from .." and "from ." as if found in
621+ # GSASII/imports directory
622+ module .__package__ = "GSASII.imports"
623+ modspec .loader .exec_module (module )
624+ # not sure if I want to do this or not
625+ sys .modules [f"GSASII.userimports.{ nam } " ] = module
626+ for member_name in dir (module ):
627+ if member_name .startswith ('_' ):
628+ continue
629+ member = getattr (module , member_name )
630+ if not callable (member ): continue
631+ for meth in ('Reader' , 'ExtensionValidator' , 'ContentsValidator' ,'UseReader' ):
632+ if not hasattr (member , meth ): break
633+ else :
634+ reader = member ()
635+ reader .formatName = '(user) ' + reader .formatName
636+ reader .longFormatName = '(user supplied) ' + reader .longFormatName
637+ if reader .UseReader :
638+ readerlist .append (reader )
639+ except Exception as msg :
640+ G2Print (f'\n Importer init: error with importer file { f !r} ' )
641+ G2Print ('Error message: {}\n ' .format (msg ))
654642 return readerlist
655643
656- # version of LoadExportRoutines from before switch to "main"
657- # def _LoadExportRoutines(parent, usetraceback=False):
658- # '''Routine to locate GSASII exporters. Warns if more than one file
659- # with the same name is in the path or if a file is found that is not
660- # in the main directory tree.
661- # '''
662- # exporterlist = []
663- # export_files = {}
664- # if '.' not in sys.path: sys.path.append('.')
665- # for path in sys.path:
666- # for filename in glob.iglob(os.path.join(path,"G2export*.py")):
667- # pkg = os.path.splitext(os.path.split(filename)[1])[0]
668- # if pkg in export_files:
669- # G2Print('Warning: exporter {} overrides {}'.format(export_files[pkg],os.path.abspath(filename)))
670- # elif not filename.startswith(GSASIIpath.path2GSAS2):
671- # G2Print('Note, found non-standard exporter: {}'.format(os.path.abspath(filename)))
672- # export_files[pkg] = filename
673- # else:
674- # export_files[pkg] = filename
675- # # go through the routines and import them, saving objects that
676- # # have export routines (method Exporter)
677- # for pkg in sorted(export_files.keys()):
678- # try:
679- # exec('import '+pkg)
680- # for clss in inspect.getmembers(eval(pkg)): # find classes defined in package
681- # if clss[0].startswith('_'): continue
682- # if not inspect.isclass(clss[1]): continue
683- # # check if we have the required methods
684- # if not hasattr(clss[1],'Exporter'): continue
685- # if not callable(getattr(clss[1],'Exporter')): continue
686- # if parent is None:
687- # if not hasattr(clss[1],'Writer'): continue
688- # else:
689- # if not hasattr(clss[1],'loadParmDict'): continue
690- # if not callable(getattr(clss[1],'loadParmDict')): continue
691- # try:
692- # exporter = clss[1](parent) # create an export instance
693- # except AttributeError:
694- # pass
695- # except Exception as exc:
696- # G2Print ('\nExport init: Error substantiating class ' + clss[0])
697- # G2Print (u'Error message: {}\n'.format(exc))
698- # if usetraceback:
699- # import traceback
700- # traceback.print_exc(file=sys.stdout)
701- # continue
702- # exporterlist.append(exporter)
703- # except AttributeError:
704- # G2Print ('Export Attribute Error ' + export_files[pkg])
705- # if usetraceback:
706- # import traceback
707- # traceback.print_exc(file=sys.stdout)
708- # except Exception as exc:
709- # G2Print ('\nExport init: Error importing file ' + export_files[pkg])
710- # G2Print (u'Error message: {}\n'.format(exc))
711- # if usetraceback:
712- # import traceback
713- # traceback.print_exc(file=sys.stdout)
714- # return exporterlist
715-
716644def LoadExportRoutines (parent , usetraceback = False ):
645+ '''Loads all export routines from the GSASII.exports area and
646+ from a user-supplied area, ~/.GSASII/exports.
647+
648+ :param parent: a reference to the main GSAS-II window when called
649+ from the GUI or None when called from GSASIIscriptable
650+ :param usetraceback: if True (used for debug only) a traceback
651+ is shown when accessing the exporter object fails
652+ :returns: a list of exporter routines (callable objects)
653+ '''
717654 from . import exports
718655 exporterlist = []
719- # how to import directly from a file for extra search magic if we need
720- # https://stackoverflow.com/questions/67631/how-can-i-import-a-module-dynamically-given-the-full-path
721- # TODO handle non-bundled readers
656+
657+ # configure exporters that have already been imported
722658 for mod_name in (_ for _ in dir (exports ) if _ .startswith ('G2export' )):
723659 mod = getattr (exports , mod_name )
724660 for member_name in dir (mod ):
725661 if member_name .startswith ('_' ):
726662 continue
727663 member = getattr (mod , member_name )
728- if not hasattr (member , 'Exporter' ):
664+ if not callable (member ): continue
665+ if not hasattr (member , 'Exporter' ): # exporters must have an exporter
729666 continue
730- if parent is None :
731- if not hasattr (member , 'Writer' ):
667+ try :
668+ if parent is None : # scripting, must also have Writer
669+ if not hasattr (member , 'Writer' ):
670+ continue
671+ exporter = member (None )
672+ else : # from GUI, must also have loadParmDict
673+ if not hasattr (member , 'loadParmDict' ):
674+ continue
675+ exporter = member (parent ) # pass the main window to the class
676+ exporterlist .append (exporter )
677+ except Exception as exc :
678+ G2Print (f'\n Export init: Error substantiating class { member_name } ' )
679+ G2Print ('Error message: {}\n ' .format (exc ))
680+ if usetraceback :
681+ import traceback
682+ traceback .print_exc (file = sys .stdout )
683+ # Now look for modules in the "user-defined" area (~/.GSASII/exports)
684+ fnam = os .path .expanduser (os .path .normpath ('~/.GSASII/exports/G2export*.py' ))
685+ import importlib .util
686+ for f in sorted (glob .glob (fnam )):
687+ nam = os .path .splitext (os .path .split (f )[1 ])[0 ]
688+ try :
689+ modspec = importlib .util .spec_from_file_location (nam , f )
690+ module = importlib .util .module_from_spec (modspec )
691+ # will process "from .." and "from ." as if found in
692+ # GSASIIexports directory
693+ module .__package__ = "GSASII.exports"
694+ modspec .loader .exec_module (module )
695+ # not sure if I want to do this or not
696+ sys .modules [f"GSASII.userexports.{ nam } " ] = module
697+ except Exception as exc :
698+ G2Print (f'\n Export init: Error with exporter file { f !r} ' )
699+ G2Print ('Error message: {}\n ' .format (exc ))
700+ if usetraceback :
701+ import traceback
702+ traceback .print_exc (file = sys .stdout )
703+ continue
704+ for member_name in dir (module ):
705+ try :
706+ if member_name .startswith ('_' ):
732707 continue
733- else :
734- if not hasattr (member , 'loadParmDict ' ):
708+ member = getattr ( module , member_name )
709+ if not hasattr (member , 'Exporter ' ): # exporters must have an exporter
735710 continue
736- try :
737- exporter = member (parent )
711+ if parent is None : # scripting, must also have Writer
712+ if not hasattr (member , 'Writer' ):
713+ continue
714+ exporter = member (None )
715+ else : # from GUI, must also have loadParmDict
716+ if not hasattr (member , 'loadParmDict' ):
717+ continue
718+ exporter = member (parent ) # pass the main window to the class
719+ exporter .formatName = '(user) ' + exporter .formatName
720+ exporter .longFormatName = '(user supplied) ' + exporter .longFormatName
721+
738722 exporterlist .append (exporter )
739723 except Exception as exc :
740- G2Print ('\n Export init: Error substantiating class ' + member_name )
724+ G2Print (f '\n Export init: Error with substantiating class { member_name } ' )
741725 G2Print ('Error message: {}\n ' .format (exc ))
742726 if usetraceback :
743727 import traceback
744728 traceback .print_exc (file = sys .stdout )
745- continue
746729 return exporterlist
747730
748-
749731def readColMetadata (imagefile ):
750732 '''Reads image metadata from a column-oriented metadata table
751733 (1-ID style .par file). Called by :func:`GetColumnMetadata`
0 commit comments