diff --git a/.codespell/ignore_lines.txt b/.codespell/ignore_lines.txt new file mode 100644 index 0000000..07fa7c8 --- /dev/null +++ b/.codespell/ignore_lines.txt @@ -0,0 +1,2 @@ +;; Please include filenames and explanations for each ignored line. +;; See https://docs.openverse.org/meta/codespell.html for docs. diff --git a/.codespell/ignore_words.txt b/.codespell/ignore_words.txt new file mode 100644 index 0000000..04b4fcf --- /dev/null +++ b/.codespell/ignore_words.txt @@ -0,0 +1,8 @@ +;; Please include explanations for each ignored word (lowercase). +;; See https://docs.openverse.org/meta/codespell.html for docs. + +;; abbreviation for "materials" often used in a journal title +mater + +;; Frobenius norm used in np.linalg.norm +fro diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..88077af --- /dev/null +++ b/.flake8 @@ -0,0 +1,13 @@ +# As of now, flake8 does not natively support configuration via pyproject.toml +# https://github.com/microsoft/vscode-flake8/issues/135 +[flake8] +exclude = + .git, + __pycache__, + build, + dist, + docs/source/conf.py +max-line-length = 79 +# Ignore some style 'errors' produced while formatting by 'black' +# https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#labels-why-pycodestyle-warnings +extend-ignore = E203 diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..86f162b --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,5 @@ +[settings] +# Keep import statement below line_length character limit +line_length = 79 +multi_line_output = 3 +include_trailing_comma = True diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..0e4a84d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,66 @@ +default_language_version: + python: python3 +ci: + autofix_commit_msg: | + [pre-commit.ci] auto fixes from pre-commit hooks + autofix_prs: true + autoupdate_branch: "pre-commit-autoupdate" + autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate" + autoupdate_schedule: monthly + skip: [no-commit-to-branch] + submodules: false +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + - id: check-case-conflict + - id: check-merge-conflict + - id: check-toml + - id: check-added-large-files + - repo: https://github.com/psf/black + rev: 24.4.2 + hooks: + - id: black + - repo: https://github.com/pycqa/flake8 + rev: 7.0.0 + hooks: + - id: flake8 + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + args: ["--profile", "black"] + - repo: https://github.com/kynan/nbstripout + rev: 0.7.1 + hooks: + - id: nbstripout + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: no-commit-to-branch + name: Prevent Commit to Main Branch + args: ["--branch", "main"] + stages: [pre-commit] + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + additional_dependencies: + - tomli + # prettier - multi formatter for .json, .yml, and .md files + - repo: https://github.com/pre-commit/mirrors-prettier + rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 + hooks: + - id: prettier + additional_dependencies: + - "prettier@^3.2.4" + # docformatter - PEP 257 compliant docstring formatter + - repo: https://github.com/s-weigand/docformatter + rev: 5757c5190d95e5449f102ace83df92e7d3b06c6c + hooks: + - id: docformatter + additional_dependencies: [tomli] + args: [--in-place, --config, ./pyproject.toml] diff --git a/AUTHORS.txt b/AUTHORS.txt index 1ea282b..cddf273 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -2,6 +2,6 @@ This code is developed by: Xiaohao Yang -This code was developed as part of the xPDFsuite project to create software -and tools for general researchers to use PDF in their work. For more +This code was developed as part of the xPDFsuite project to create software +and tools for general researchers to use PDF in their work. For more information on the DiffPy project email sb2896@columbia.edu diff --git a/README.rst b/README.rst index 720412f..e78479f 100644 --- a/README.rst +++ b/README.rst @@ -17,13 +17,13 @@ INSTALLATION ------------------------------------------------------------------------ We are going to release conda package for all platform. For general user -please use the installation file and install software. For developor, +please use the installation file and install software. For developor, you can install dpx.confutils using python setup.py install - -Note: the dependency is not specified in the setup.py. You need to install -them yourself. You can use Anaconda or other python enviroment. + +Note: the dependency is not specified in the setup.py. You need to install +them yourself. You can use Anaconda or other python enviroment. CONTACTS @@ -33,4 +33,4 @@ For more information on diffpy.Structure please visit the project web-page http://www.diffpy.org/ -or email Prof. Simon Billinge at sb2896@columbia.edu. \ No newline at end of file +or email Prof. Simon Billinge at sb2896@columbia.edu. diff --git a/requirements/pip.txt b/requirements/pip.txt index f8d7a2e..59ebc00 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -1,4 +1,4 @@ numpy configparser traits -traitsui \ No newline at end of file +traitsui diff --git a/src/diffpy/__init__.py b/src/diffpy/__init__.py index 1988b11..815245d 100644 --- a/src/diffpy/__init__.py +++ b/src/diffpy/__init__.py @@ -11,11 +11,8 @@ # See LICENSENOTICE.txt for license information. # ############################################################################## +"""Blank namespace package.""" -""" -Blank namespace package. -""" - -__import__('pkg_resources').declare_namespace(__name__) +__import__("pkg_resources").declare_namespace(__name__) # End of file diff --git a/src/diffpy/srxconfutils/__init__.py b/src/diffpy/srxconfutils/__init__.py index 7b91ed3..29aa678 100644 --- a/src/diffpy/srxconfutils/__init__.py +++ b/src/diffpy/srxconfutils/__init__.py @@ -12,18 +12,21 @@ # ############################################################################## +# some convenience imports +from diffpy.srxconfutils.config import ConfigBase + # package version from diffpy.srxconfutils.version import __version__ -# some convenience imports -from diffpy.srxconfutils.config import ConfigBase, ConfigBase # unit tests def test(): - '''Execute all unit tests for the diffpy.pdfgetx package. + """Execute all unit tests for the diffpy.pdfgetx package. + Return a unittest TestResult object. - ''' + """ from dpx.confutils.tests import test + return test() diff --git a/src/diffpy/srxconfutils/config.py b/src/diffpy/srxconfutils/config.py index d5742bf..77a0afe 100644 --- a/src/diffpy/srxconfutils/config.py +++ b/src/diffpy/srxconfutils/config.py @@ -11,48 +11,55 @@ # See LICENSENOTICE.txt for license information. # ############################################################################## +"""Package for organizing program configurations. It can read/write +configurations file, parse arguments from command lines, and also parse +arguments passed from method/function calling inside python. -''' -package for organizing program configurations. It can read/write configurations -file, parse arguments from command lines, and also parse arguments passed from -method/function calling inside python. - Note: for python 2.6, argparse and orderedDict is required, install them with easy_install -''' +""" -from configparser import ConfigParser -import re +import argparse import os +import re import sys +from configparser import ConfigParser from functools import partial -import argparse + try: from collections import OrderedDict except: from ordereddict import OrderedDict -from diffpy.srxconfutils.tools import _configPropertyRad, _configPropertyR, \ - _configPropertyRW, str2bool, opt2Str, str2Opt, StrConv, FakeConfigFile +from diffpy.srxconfutils.tools import ( + FakeConfigFile, + StrConv, + _configPropertyR, + _configPropertyRad, + _configPropertyRW, + opt2Str, + str2bool, + str2Opt, +) + class ConfigBase(object): - ''' - _optdatalist_default, _optdatalist are metadata used to - initialize the options, see below for examples - + """_optdatalist_default, _optdatalist are metadata used to + initialize the options, see below for examples. + options presents in --help (in cmd), config file, headers have same order as in these list, so arrange them in right order here. - + optional args to control if the options presents in args, config file or file header - + 'args' - default is 'a' if 'a', this option will be available in self.args if 'n', this option will not be available in self.args 'config' - default is 'a' if 'f', this option will present in self.config and be written to - config file only in full mode + config file only in full mode if 'a', this option will present in self.config and be written to config file both in full and short mode if 'n', this option will not present in self.config @@ -61,25 +68,23 @@ class ConfigBase(object): if 'a', this option will be written to header both in full and short mode if 'n', this option will not be written to header - + so in short mode, all options with 'a' will be written, in full mode, all options with 'a' or 'f' will be written - ''' + """ # Text to display before the argument help - _description = \ - '''Description of configurations - ''' + _description = """Description of configurations + """ # Text to display after the argument help - _epilog = \ - ''' - ''' + _epilog = """ + """ - ''' + """ optdata contains these keys: these args will be passed to argparse, see the documents of argparse for detail information - + 'f': full, (positional) 's': short 'h': help @@ -91,100 +96,170 @@ class ConfigBase(object): 'r': required 'de': dest 'co': const - ''' - _optdatanamedict = {'h':'help', - 't':'type', - 'a':'action', - 'n':'nargs', - 'd':'default', - 'c':'choices', - 'r':'required', - 'de':'dest', - 'co':'const'} + """ + _optdatanamedict = { + "h": "help", + "t": "type", + "a": "action", + "n": "nargs", + "d": "default", + "c": "choices", + "r": "required", + "de": "dest", + "co": "const", + } # examples, overload it _optdatalist_default = [ - ['configfile', {'sec':'Control', 'config':'f', 'header':'n', - 's':'c', - 'h':'name of input config file', - 'd':'', }], - ['createconfig', {'sec':'Control', 'config':'n', 'header':'n', - 'h':'create a config file according to default or current values', - 'd':'', }], - ['createconfigfull', {'sec':'Control', 'config':'n', 'header':'n', - 'h':'create a full configurable config file', - 'd':'', }], - ] + [ + "configfile", + { + "sec": "Control", + "config": "f", + "header": "n", + "s": "c", + "h": "name of input config file", + "d": "", + }, + ], + [ + "createconfig", + { + "sec": "Control", + "config": "n", + "header": "n", + "h": "create a config file according to default or current values", + "d": "", + }, + ], + [ + "createconfigfull", + { + "sec": "Control", + "config": "n", + "header": "n", + "h": "create a full configurable config file", + "d": "", + }, + ], + ] # examples, overload it _optdatalist = [ - ['tifdirectory', {'sec':'Experiment', 'header':'n', - 's':'tifdir', - 'h':'directory of raw tif files', - 'd':'currentdir', }], - ['integrationspace', {'sec':'Experiment', - 'h':'integration space, could be twotheta or qspace', - 'd':'twotheta', - 'c':['twotheta', 'qspace'], }], - ['wavelength', {'sec':'Experiment', - 'h':'wavelength of x-ray, in A', - 'd':0.1000, }], - ['rotationd', {'sec':'Experiment', - 's':'rot', - 'h':'rotation angle of tilt plane, in degree', - 'd':0.0, }], - ['includepattern', {'sec':'Beamline', - 's':'ipattern', - 'h':'file name pattern for included files', - 'n':'*', - 'd':['*.tif'], }], - ['excludepattern', {'sec':'Beamline', - 's':'epattern', - 'h':'file name pattern for excluded files', - 'n':'*', - 'd':['*.dark.tif', '*.raw.tif'], }], - ['fliphorizontal', {'sec':'Beamline', - 'h':'filp the image horizontally', - 'n':'?', - 'co':True, - 'd':False, }], - ['regulartmatrixenable', {'sec':'Others', - 'h':'normalize tmatrix in splitting method', - 'n':'?', - 'co':True, - 'd':False, }], - ['maskedges', {'sec':'Others', 'config':'f', 'header':'f', - 'h':'mask the edge pixels, first four means the number of pixels masked in each edge \ - (left, right, top, bottom), the last one is the radius of a region masked around the corner', - 'n':5, - 'd':[1, 1, 1, 1, 50], }], - ] + [ + "tifdirectory", + { + "sec": "Experiment", + "header": "n", + "s": "tifdir", + "h": "directory of raw tif files", + "d": "currentdir", + }, + ], + [ + "integrationspace", + { + "sec": "Experiment", + "h": "integration space, could be twotheta or qspace", + "d": "twotheta", + "c": ["twotheta", "qspace"], + }, + ], + [ + "wavelength", + { + "sec": "Experiment", + "h": "wavelength of x-ray, in A", + "d": 0.1000, + }, + ], + [ + "rotationd", + { + "sec": "Experiment", + "s": "rot", + "h": "rotation angle of tilt plane, in degree", + "d": 0.0, + }, + ], + [ + "includepattern", + { + "sec": "Beamline", + "s": "ipattern", + "h": "file name pattern for included files", + "n": "*", + "d": ["*.tif"], + }, + ], + [ + "excludepattern", + { + "sec": "Beamline", + "s": "epattern", + "h": "file name pattern for excluded files", + "n": "*", + "d": ["*.dark.tif", "*.raw.tif"], + }, + ], + [ + "fliphorizontal", + { + "sec": "Beamline", + "h": "filp the image horizontally", + "n": "?", + "co": True, + "d": False, + }, + ], + [ + "regulartmatrixenable", + { + "sec": "Others", + "h": "normalize tmatrix in splitting method", + "n": "?", + "co": True, + "d": False, + }, + ], + [ + "maskedges", + { + "sec": "Others", + "config": "f", + "header": "f", + "h": "mask the edge pixels, first four means the number of pixels masked in each edge \ + (left, right, top, bottom), the last one is the radius of a region masked around the corner", + "n": 5, + "d": [1, 1, 1, 1, 50], + }, + ], + ] # some default data # configfile: default config file name # headertitle: default title of header - _defaultdata = {'configfile': ['config.cfg'], - 'headertitle': 'Configuration information' - } - + _defaultdata = { + "configfile": ["config.cfg"], + "headertitle": "Configuration information", + } def __init__(self, filename=None, args=None, **kwargs): - ''' - init the class and update the values of options if specified in - filename/args/kwargs - + """Init the class and update the values of options if specified + in filename/args/kwargs. + it will: 1. call self._preInit method 2. find the config file if specified in filename/args/kwargs if failed, try to find default config file 3. update the options value using filename/args/kwargs file > args > kwargs - + :param filename: str, file name of the config file :param args: list of str, args passed from cmd :param kwargs: dict, optional kwargs - + :return: None - ''' + """ # call self._preInit self._preInit(**kwargs) @@ -195,11 +270,11 @@ def __init__(self, filename=None, args=None, **kwargs): # example, overload it def _preInit(self, **kwargs): - ''' - method called in init process, overload it! - - this method will be called before reading config from file/args/kwargs - ''' + """Method called in init process, overload it! + + this method will be called before reading config from + file/args/kwargs + """ # for name in ['rotation']: # setattr(self.__class__, name, _configPropertyRad(name+'d')) # self._configlist['Experiment'].extend(['rotation']) @@ -208,62 +283,58 @@ def _preInit(self, **kwargs): ########################################################################### def _findConfigFile(self, filename=None, args=None, **kwargs): - ''' - find config file, if any config is specified in filename/args/kwargs - then return the filename of config. - + """Find config file, if any config is specified in + filename/args/kwargs then return the filename of config. + :param filename: str, file name of config file :param filename: list of str, args passed from cmd :param kwargs: optional kwargs - - :return: name of config file if found, otherwise None - ''' + :return: name of config file if found, otherwise None + """ rv = None - if (filename != None): + if filename != None: rv = filename - if (args != None): - if ('--configfile' in args) or ('-c' in args): + if args != None: + if ("--configfile" in args) or ("-c" in args): obj = self.args.parse_args(args) rv = obj.configfile - if 'configfile' in kwargs: - rv = kwargs['configfile'] + if "configfile" in kwargs: + rv = kwargs["configfile"] return rv def _findDefaultConfigFile(self, filename=None, args=None, **kwargs): - ''' - find default config file, if any config is specified in - filename/args/kwargs or in self._defaultdata['configfile'], then return - the filename of config. - + """Find default config file, if any config is specified in + filename/args/kwargs or in self._defaultdata['configfile'], then + return the filename of config. + kwargs > args > filename > default - + param filename: str, file name of config file param filename: list of str, args passed from cmd param kwargs: optional kwargs - - return: name of config file if found, otherwise None - ''' + + return: name of config file if found, otherwise None + """ rv = self._findConfigFile(filename, args, **kwargs) if rv == None: - for dconf in self._defaultdata['configfile']: - if (os.path.exists(dconf))and(rv == None): + for dconf in self._defaultdata["configfile"]: + if (os.path.exists(dconf)) and (rv == None): rv = dconf return rv ########################################################################### def _updateSelf(self, optnames=None, **kwargs): - ''' - update the options value, then copy the values in the self.'options' to - self.config - + """Update the options value, then copy the values in the + self.'options' to self.config. + 1. call self._preUpdateSelf 2. apply options' value from *self.option* to self.config 3. call self._postUpdateSelf - + :param optnames: str or list of str, name of options whose value has been changed, if None, update all options - ''' + """ # so some check right here self._preUpdateSelf(**kwargs) # copy value to self.config @@ -274,90 +345,78 @@ def _updateSelf(self, optnames=None, **kwargs): # example, overload it def _preUpdateSelf(self, **kwargs): - ''' - additional process called in self._updateSelf, this method is called - before self._copySelftoConfig(), i.e. before copy options value to - self.config (config file) - ''' + """Additional process called in self._updateSelf, this method is + called before self._copySelftoConfig(), i.e. before copy options + value to self.config (config file)""" return def _postUpdateSelf(self, **kwargs): - ''' - additional process called in self._updateSelf, this method is called - after self._copySelftoConfig(), i.e. before copy options value to - self.config (config file) - ''' + """Additional process called in self._updateSelf, this method is + called after self._copySelftoConfig(), i.e. before copy options + value to self.config (config file)""" return ########################################################################### def _getTypeStr(self, optname): - ''' - return the type of option - + """Return the type of option. + :param optname: str, name of option - - :return: string, type of the option - ''' + :return: string, type of the option + """ opttype = self._getTypeStrC(optname) return opttype @classmethod def _getTypeStrC(cls, optname): - ''' - class method, return the type of option - first try to get type information from metadata, if failed, try - to get type from default value - + """Class method, return the type of option first try to get type + information from metadata, if failed, try to get type from + default value. + :param optname: str, name of option - - :return: string, type of the option - ''' + :return: string, type of the option + """ optdata = cls._optdata[optname] - if 't' in optdata: - opttype = optdata['t'] + if "t" in optdata: + opttype = optdata["t"] else: - value = optdata['d'] + value = optdata["d"] if isinstance(value, str): - opttype = 'str' + opttype = "str" elif isinstance(value, bool): - opttype = 'bool' + opttype = "bool" elif isinstance(value, float): - opttype = 'float' + opttype = "float" elif isinstance(value, int): - opttype = 'int' + opttype = "int" elif isinstance(value, list): if len(value) == 0: - opttype = 'strlist' + opttype = "strlist" elif isinstance(value[0], str): - opttype = 'strlist' + opttype = "strlist" elif isinstance(value[0], bool): - opttype = 'boollist' + opttype = "boollist" elif isinstance(value[0], float): - opttype = 'floatlist' + opttype = "floatlist" elif isinstance(value[0], int): - opttype = 'intlist' + opttype = "intlist" return opttype ########################################################################### def _detectAddSections(self): - ''' - detect sections present in self._optdata and add them to self.config - also add it to self._configlist - ''' + """Detect sections present in self._optdata and add them to + self.config also add it to self._configlist.""" self._detectAddSectionsC(self) return @classmethod def _detectAddSectionsC(cls): - ''' - class method, detect sections present in self._optdata and add them to self.config - also add it to self._configlist - ''' + """Class method, detect sections present in self._optdata and + add them to self.config also add it to self._configlist.""" # seclist = [self._optdata[key]['sec'] for key in self._optdata.keys()] - seclist = [cls._optdata[opt[0]]['sec'] for opt in cls._optdatalist] + seclist = [cls._optdata[opt[0]]["sec"] for opt in cls._optdatalist] secdict = OrderedDict.fromkeys(seclist) # for sec in set(seclist): for sec in secdict.keys(): @@ -366,75 +425,80 @@ class method, detect sections present in self._optdata and add them to self.conf return def _addOpt(self, optname): - ''' - add options to self.config and self.args and self.*option*, - this will read metadata from self._optdatalist - + """Add options to self.config and self.args and self.*option*, + this will read metadata from self._optdatalist. + :param optname: string, name of option - ''' + """ self._addOptC(self, optname) return @classmethod def _addOptC(cls, optname): - ''' - Class method, add options to self.config and self.args and - self.*option*, this will read metadata in self._optdatalist - + """Class method, add options to self.config and self.args and + self.*option*, this will read metadata in self._optdatalist. + :param optname: string, name of option - ''' + """ optdata = cls._optdata[optname] opttype = cls._getTypeStrC(optname) # replace currentdir in default to os.getcwd() - if optdata['d'] == 'currentdir': - optdata['d'] = os.getcwd() + if optdata["d"] == "currentdir": + optdata["d"] = os.getcwd() # add to cls.'optname' cls._addOptSelfC(optname, optdata) # add to cls.config - secname = optdata['sec'] if 'sec' in optdata else 'Others' + secname = optdata["sec"] if "sec" in optdata else "Others" cls._configlist[secname].append(optname) - if optdata.get('config', 'a') != 'n': - strvalue = ', '.join(map(str, optdata['d'])) if isinstance(optdata['d'], list) else str(optdata['d']) + if optdata.get("config", "a") != "n": + strvalue = ( + ", ".join(map(str, optdata["d"])) + if isinstance(optdata["d"], list) + else str(optdata["d"]) + ) cls.config.set(secname, optname, strvalue) # add to cls.args - if optdata.get('args', 'a') != 'n': + if optdata.get("args", "a") != "n": # transform optdata to a dict that can pass to add_argument method pargs = dict() for key in optdata.keys(): if key in cls._optdatanamedict: pargs[cls._optdatanamedict[key]] = optdata[key] - pargs['default'] = argparse.SUPPRESS - pargs['type'] = StrConv(opttype) + pargs["default"] = argparse.SUPPRESS + pargs["type"] = StrConv(opttype) # add args - if 'f' in optdata: + if "f" in optdata: cls.args.add_argument(optname, **pargs) - elif 's' in optdata: - cls.args.add_argument('--' + optname, '-' + optdata['s'], **pargs) + elif "s" in optdata: + cls.args.add_argument( + "--" + optname, "-" + optdata["s"], **pargs + ) else: - cls.args.add_argument('--' + optname, **pargs) + cls.args.add_argument("--" + optname, **pargs) return @classmethod def _addOptSelfC(cls, optname, optdata): - ''' - class method, assign options value to *self.option*, using metadata - + """Class method, assign options value to *self.option*, using + metadata. + :param optname: string, name of the option - :param optdata: dict, metadata of the options, get it from self._optdatalist - ''' - setattr(cls, optname, optdata['d']) + :param optdata: dict, metadata of the options, get it from + self._optdatalist + """ + setattr(cls, optname, optdata["d"]) return def _copyConfigtoSelf(self, optnames=None): - ''' - copy the options' value from self.config to self.*option* - - :param optnames: str or list of str, names of options whose value copied - from self.config to self.*option*'. Set None to update all - ''' + """Copy the options' value from self.config to self.*option* + + :param optnames: str or list of str, names of options whose + value copied from self.config to self.*option*'. Set None to + update all + """ if optnames != None: optnames = optnames if isinstance(optnames, list) else [optnames] else: @@ -444,19 +508,19 @@ def _copyConfigtoSelf(self, optnames=None): for optname in optnames: if optname in self._optdata: - secname = self._optdata[optname]['sec'] + secname = self._optdata[optname]["sec"] opttype = self._getTypeStr(optname) optvalue = self.config.get(secname, optname) setattr(self, optname, str2Opt(opttype, optvalue)) return def _copySelftoConfig(self, optnames=None): - ''' - copy the value from self.*option* to self.config - - :param optname: str or list of str, names of options whose value copied - from self.*option* to self.config. Set None to update all - ''' + """Copy the value from self.*option* to self.config. + + :param optname: str or list of str, names of options whose value + copied from self.*option* to self.config. Set None to update + all + """ if optnames != None: optnames = optnames if isinstance(optnames, list) else [optnames] else: @@ -466,7 +530,7 @@ def _copySelftoConfig(self, optnames=None): for optname in optnames: if optname in self._optdata: - secname = self._optdata[optname]['sec'] + secname = self._optdata[optname]["sec"] opttype = self._getTypeStr(optname) optvalue = getattr(self, optname) self.config.set(secname, optname, opt2Str(opttype, optvalue)) @@ -475,12 +539,12 @@ def _copySelftoConfig(self, optnames=None): ########################################################################### def parseArgs(self, pargs): - ''' - parse args and update the value in self.*option*, this will call the - self.args() to parse args, - - :param pargs: list of string, arguments to parse, usually comming from sys.argv - ''' + """Parse args and update the value in self.*option*, this will + call the self.args() to parse args, + + :param pargs: list of string, arguments to parse, usually + comming from sys.argv + """ obj = self.args.parse_args(pargs) changedargs = obj.__dict__.keys() for optname in changedargs: @@ -492,11 +556,10 @@ def parseArgs(self, pargs): return obj def parseKwargs(self, **kwargs): - ''' - update self.*option* values according to the kwargs - + """Update self.*option* values according to the kwargs. + :param kwargs: dict, keywords=value - ''' + """ if kwargs != {}: changedargs = [] for optname, optvalue in kwargs.items(): @@ -508,11 +571,10 @@ def parseKwargs(self, **kwargs): return def parseConfigFile(self, filename): - ''' - read a config file and update the self.*option* - + """Read a config file and update the self.*option* + :param filename: str, file name of config file (include path) - ''' + """ if filename != None: filename = os.path.abspath(filename) if os.path.exists(filename): @@ -526,21 +588,21 @@ def parseConfigFile(self, filename): return def updateConfig(self, filename=None, args=None, **kwargs): - ''' - update config according to config file, args(from sys.argv) or **kwargs - + """Update config according to config file, args(from sys.argv) + or **kwargs. + 1. call self._preUpdateConfig() - 2. process file/args/kwargs passed to this method, + 2. process file/args/kwargs passed to this method, 3. read a configfile if specified in args or kwargs 4. call self._postUpdateConfig() 5. write config file if specified in args/kwargs - + :param filename: str, file name of the config file - :param args: list of str, args passed from cmd, + :param args: list of str, args passed from cmd, :param kwargs: dict, optional kwargs - + :return: True if anything updated, False if nothing updated - ''' + """ # call self._preUpdateConfig self._preUpdateConfig(**kwargs) @@ -552,7 +614,11 @@ def updateConfig(self, filename=None, args=None, **kwargs): if kwargs != {}: rv = self.parseKwargs(**kwargs) - if (filename == None)and((args == None)or(args == []))and(kwargs == {}): + if ( + (filename == None) + and ((args == None) or (args == [])) + and (kwargs == {}) + ): rv = self._updateSelf() # call self._callbackUpdateConfig @@ -563,87 +629,107 @@ def updateConfig(self, filename=None, args=None, **kwargs): return rv def _preUpdateConfig(self, **kwargs): - ''' - Method called before parsing args or kwargs or config file, in self.updateConfig - ''' + """Method called before parsing args or kwargs or config file, + in self.updateConfig.""" return def _postUpdateConfig(self, **kwargs): - ''' - Method called after parsing args or kwargs or config file, in self.updateConfig - ''' + """Method called after parsing args or kwargs or config file, in + self.updateConfig.""" return ########################################################################### def _createConfigFile(self): - ''' - write output config file if specfied in configuration - the filename is specified by self.createconfig - ''' - if (self.createconfig != '')and(self.createconfig != None): - self.writeConfig(self.createconfig, 'short') - self.createconfig = '' - if (self.createconfigfull != '')and(self.createconfigfull != None): - self.writeConfig(self.createconfigfull, 'full') - self.createconfigfull = '' + """Write output config file if specfied in configuration the + filename is specified by self.createconfig.""" + if (self.createconfig != "") and (self.createconfig != None): + self.writeConfig(self.createconfig, "short") + self.createconfig = "" + if (self.createconfigfull != "") and (self.createconfigfull != None): + self.writeConfig(self.createconfigfull, "full") + self.createconfigfull = "" return - def writeConfig(self, filename, mode='short', changeconfigfile=True): - ''' - write config to file. the file is compatiable with python package ConfigParser - + def writeConfig(self, filename, mode="short", changeconfigfile=True): + """Write config to file. the file is compatiable with python + package ConfigParser. + :param filename: string, name of file - :param mode: string, 'short' or 'full' ('s' or 'f'). - in short mode, all options with 'a' will be written, in full mode, + :param mode: string, 'short' or 'full' ('s' or 'f'). in short + mode, all options with 'a' will be written, in full mode, all options with 'a' or 'f' will be written - ''' + """ if changeconfigfile: self.configfile = os.path.abspath(filename) self._updateSelf() # func decide if wirte the option to config according to mode # options not present in self._optdata will not be written to config - if mode.startswith('s'): - mcond = lambda optname: self._optdata.get(optname, {'config':'n'}).get('config', 'a') == 'a' + if mode.startswith("s"): + mcond = ( + lambda optname: self._optdata.get( + optname, {"config": "n"} + ).get("config", "a") + == "a" + ) else: - mcond = lambda optname: self._optdata.get(optname, {'config':'n'}).get('config', 'a') != 'n' + mcond = ( + lambda optname: self._optdata.get( + optname, {"config": "n"} + ).get("config", "a") + != "n" + ) lines = [] for section in self.config._sections: tlines = [] - for (key, value) in self.config._sections[section].items(): + for key, value in self.config._sections[section].items(): if (key != "__name__") and mcond(key): - tlines.append("%s = %s" % (key, str(value).replace('\n', '\n\t'))) + tlines.append( + "%s = %s" % (key, str(value).replace("\n", "\n\t")) + ) if len(tlines) > 0: lines.append("[%s]" % section) lines.extend(tlines) - lines.append('') + lines.append("") rv = "\n".join(lines) + "\n" - fp = open(filename, 'w') + fp = open(filename, "w") fp.write(rv) fp.close() return - def getHeader(self, title=None, mode='full'): - ''' - get a header of configurations values, - - :param title: str, title of header, if None, try to get it from self.defaultvalue - :param mode: string, 'short' or 'full' ('s' or 'f'). - in short mode, all options with 'a' will be written, in full mode, + def getHeader(self, title=None, mode="full"): + """Get a header of configurations values, + + :param title: str, title of header, if None, try to get it from + self.defaultvalue + :param mode: string, 'short' or 'full' ('s' or 'f'). in short + mode, all options with 'a' will be written, in full mode, all options with 'a' or 'f' will be written - - :return: string, lines with line break that can be directly writen to a text file - ''' + :return: string, lines with line break that can be directly + writen to a text file + """ lines = [] - title = '# %s #' % (self._defaultdata['headertitle'] if title == None else title) + title = "# %s #" % ( + self._defaultdata["headertitle"] if title == None else title + ) lines.append(title) # func decide if wirte the option to header according to mode # options not present in self._optdata will not be written to header - if mode.startswith('s'): - mcond = lambda optname: self._optdata.get(optname, {'header':'n'}).get('header', 'a') == 'a' + if mode.startswith("s"): + mcond = ( + lambda optname: self._optdata.get( + optname, {"header": "n"} + ).get("header", "a") + == "a" + ) else: - mcond = lambda optname: self._optdata.get(optname, {'header':'n'}).get('header', 'a') != 'n' + mcond = ( + lambda optname: self._optdata.get( + optname, {"header": "n"} + ).get("header", "a") + != "n" + ) for secname in self._configlist.keys(): tlines = [] @@ -651,46 +737,51 @@ def getHeader(self, title=None, mode='full'): if mcond(optname): value = getattr(self, optname) ttype = self._getTypeStr(optname) - strvalue = ', '.join(map(str, value)) if ttype.endswith('list') else str(value) + strvalue = ( + ", ".join(map(str, value)) + if ttype.endswith("list") + else str(value) + ) tlines.append("%s = %s" % (optname, strvalue)) if len(tlines) > 0: lines.append("[%s]" % secname) lines.extend(tlines) - lines.append('') + lines.append("") rv = "\n".join(lines) + "\n" return rv def resetDefault(self, optnames=None): - ''' - reset all values to their default value - - :param optnames: list of str, name of options to reset, None for all options - ''' + """Reset all values to their default value. + + :param optnames: list of str, name of options to reset, None for + all options + """ if optnames == None: optnames = self._optdata.keys() for optname in optnames: if optname in self._optdata: - setattr(self, optname, self._optdata[optname]['d']) + setattr(self, optname, self._optdata[optname]["d"]) self._updateSelf() return ########################################################################### - #IMPORTANT call this method if you want to add options as class attributes!!! + # IMPORTANT call this method if you want to add options as class attributes!!! @classmethod def initConfigClass(cls): - ''' - init config class and add options to class - - IMPORTANT call this method after you define the metadata of your config - class to add options as class attributes!!! - ''' + """Init config class and add options to class. + + IMPORTANT call this method after you define the metadata of your + config class to add options as class attributes!!! + """ cls._preInitConfigClass() cls.config = ConfigParser(dict_type=OrderedDict) - cls.args = argparse.ArgumentParser(description=cls._description, - epilog=cls._epilog, - formatter_class=argparse.RawDescriptionHelpFormatter) + cls.args = argparse.ArgumentParser( + description=cls._description, + epilog=cls._epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) cls._configlist = OrderedDict({}) cls._optdatalist = cls._optdatalist_default + cls._optdatalist @@ -705,28 +796,27 @@ class to add options as class attributes!!! @classmethod def _postInitConfigClass(cls): - ''' - additional processes called after initConfigClass - + """Additional processes called after initConfigClass. + overload it - ''' + """ pass @classmethod def _preInitConfigClass(cls): - ''' - additional processes called before initConfigClass - + """Additional processes called before initConfigClass. + overload it - ''' + """ pass -#VERY IMPORTANT!!! + +# VERY IMPORTANT!!! # add options to class # initConfigClass(ConfigBase) # ConfigBase.initConfigClass() -if __name__ == '__main__': +if __name__ == "__main__": test = ConfigBase() test.updateConfig() diff --git a/src/diffpy/srxconfutils/configtraits.py b/src/diffpy/srxconfutils/configtraits.py index 0262dec..d71b84f 100644 --- a/src/diffpy/srxconfutils/configtraits.py +++ b/src/diffpy/srxconfutils/configtraits.py @@ -11,50 +11,73 @@ # See LICENSENOTICE.txt for license information. # ############################################################################## - -''' -package for organizing program configurations. It can read/write configurations -file, parse arguments from command lines, and also parse arguments passed from -method/function calling inside python. +"""Package for organizing program configurations. It can read/write +configurations file, parse arguments from command lines, and also parse +arguments passed from method/function calling inside python. This one is similar to ConfigBase but use Traits, so every option (self.*option* is a trait) Note: for python 2.6, argparse and orderedDict is required, install them with easy_install -''' +""" -from configparser import ConfigParser -import re +import argparse import os +import re import sys +from configparser import ConfigParser from functools import partial -import argparse -from traits.api import Directory, String, List, Enum, Bool, File, Float, Int, \ - HasTraits, Property, Range, cached_property, Str, Instance, Array,\ - Event, CFloat, CInt, on_trait_change -from traitsui.api import Item, Group, View +from traits.api import ( + Array, + Bool, + CFloat, + CInt, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + String, + cached_property, + on_trait_change, +) +from traitsui.api import Group, Item, View -from diffpy.srxconfutils.tools import _configPropertyRad, _configPropertyR, _configPropertyRW, \ - str2bool, opt2Str, str2Opt, StrConv from diffpy.srxconfutils.config import ConfigBase +from diffpy.srxconfutils.tools import ( + StrConv, + _configPropertyR, + _configPropertyRad, + _configPropertyRW, + opt2Str, + str2bool, + str2Opt, +) + class ConfigBaseTraits(HasTraits, ConfigBase): - ''' - _optdatalist_default, _optdatalist are metadata used to - initialize the options, see below for examples - + """_optdatalist_default, _optdatalist are metadata used to + initialize the options, see below for examples. + options presents in --help (in cmd), config file, headers have same order as in these list, so arrange them in right order here. - + optional args to control if the options presents in args, config file or file header - + 'args' - default is 'a' if 'a', this option will be available in self.args if 'n', this option will not be available in self.args 'config' - default is 'a' if 'f', this option will present in self.config and be written to - config file only in full mode + config file only in full mode if 'a', this option will present in self.config and be written to config file both in full and short mode if 'n', this option will not present in self.config @@ -63,25 +86,23 @@ class ConfigBaseTraits(HasTraits, ConfigBase): if 'a', this option will be written to header both in full and short mode if 'n', this option will not be written to header - + so in short mode, all options with 'a' will be written, in full mode, all options with 'a' or 'f' will be written - ''' - + """ + # Text to display before the argument help - _description = \ - '''Description of configurations - ''' + _description = """Description of configurations + """ # Text to display after the argument help - _epilog = \ - ''' - ''' - - ''' + _epilog = """ + """ + + """ optdata contains these keys: these args will be passed to argparse, see the documents of argparse for detail information - + 'f': full, (positional) 's': short 'h': help @@ -93,108 +114,179 @@ class ConfigBaseTraits(HasTraits, ConfigBase): 'r': required 'de': dest 'co': const - + additional options for traits: 'tt': traits type 'l': traits label - ''' - _optdatanamedict = {'h':'help', - 't':'type', - 'a':'action', - 'n':'nargs', - 'd':'default', - 'c':'choices', - 'r':'required', - 'de':'dest', - 'co':'const'} + """ + _optdatanamedict = { + "h": "help", + "t": "type", + "a": "action", + "n": "nargs", + "d": "default", + "c": "choices", + "r": "required", + "de": "dest", + "co": "const", + } _traitstypedict = { - 'str': String, - 'int': CInt, - 'float': CFloat, - 'bool': Bool, - 'file': File, - 'directory': Directory, - 'strlist':List, - 'intlist':List, - 'floatlist':List, - 'boollist':List, - 'array':Array, - } - - #examples, overload it + "str": String, + "int": CInt, + "float": CFloat, + "bool": Bool, + "file": File, + "directory": Directory, + "strlist": List, + "intlist": List, + "floatlist": List, + "boollist": List, + "array": Array, + } + + # examples, overload it _optdatalist_default = [ - ['configfile',{'sec':'Control', 'config':'f', 'header':'n', - 'l':'Config File', - 'tt':'file', - 's':'c', - 'h':'name of input config file', - 'd':'',}], - ['createconfig',{'sec':'Control', 'config':'n', 'header':'n', - 'h':'create a config file according to default or current values', - 'd':'',}], - ['createconfigfull',{'sec':'Control', 'config':'n', 'header':'n', - 'h':'create a full configurable config file', - 'd':'',}], - ] - #examples, overload it + [ + "configfile", + { + "sec": "Control", + "config": "f", + "header": "n", + "l": "Config File", + "tt": "file", + "s": "c", + "h": "name of input config file", + "d": "", + }, + ], + [ + "createconfig", + { + "sec": "Control", + "config": "n", + "header": "n", + "h": "create a config file according to default or current values", + "d": "", + }, + ], + [ + "createconfigfull", + { + "sec": "Control", + "config": "n", + "header": "n", + "h": "create a full configurable config file", + "d": "", + }, + ], + ] + # examples, overload it _optdatalist = [ - ['tifdirectory',{'sec':'Experiment', 'header':'n', - 'tt':'directory', - 'l':'Tif directory', - 's':'tifdir', - 'h':'directory of raw tif files', - 'd':'currentdir',}], - ['integrationspace',{'sec':'Experiment', - 'l':'Integration space', - 'h':'integration space, could be twotheta or qspace', - 'd':'twotheta', - 'c':['twotheta','qspace'],}], - ['wavelength',{'sec':'Experiment', - 'l':'Wavelength', - 'h':'wavelength of x-ray, in A', - 'd':0.1000,}], - ['rotationd',{'sec':'Experiment', - 'l':'Tilt Rotation', - 's':'rot', - 'h':'rotation angle of tilt plane, in degree', - 'd':0.0,}], - ['includepattern',{'sec':'Beamline','header':'n','config':'f', - 'l':'Include', - 's':'ipattern', - 'h':'file name pattern for included files', - 'n':'*', - 'd':['*.tif'],}], - ['excludepattern',{'sec':'Beamline','header':'n','config':'f', - 'l':'Exclude', - 's':'epattern', - 'h':'file name pattern for excluded files', - 'n':'*', - 'd':['*.dark.tif', '*.raw.tif'],}], - ['fliphorizontal',{'sec':'Beamline','header':'n','config':'f', - 'l':'Filp horizontally', - 'h':'filp the image horizontally', - 'n':'?', - 'co':True, - 'd':False,}], - ['maskedges',{'sec':'Others','config':'f', - 'tt':'array', - 'l':'Mask edges', - 'h':'mask the edge pixels, first four means the number of pixels masked in each edge \ - (left, right, top, bottom), the last one is the radius of a region masked around the corner', - 'n':5, - 'd':[10,10,10,10,100],}], - ] - - #default config file path and name - _defaultdata = {'configfile': ['config.cfg'], - 'headertitle': 'Configuration information' - } - + [ + "tifdirectory", + { + "sec": "Experiment", + "header": "n", + "tt": "directory", + "l": "Tif directory", + "s": "tifdir", + "h": "directory of raw tif files", + "d": "currentdir", + }, + ], + [ + "integrationspace", + { + "sec": "Experiment", + "l": "Integration space", + "h": "integration space, could be twotheta or qspace", + "d": "twotheta", + "c": ["twotheta", "qspace"], + }, + ], + [ + "wavelength", + { + "sec": "Experiment", + "l": "Wavelength", + "h": "wavelength of x-ray, in A", + "d": 0.1000, + }, + ], + [ + "rotationd", + { + "sec": "Experiment", + "l": "Tilt Rotation", + "s": "rot", + "h": "rotation angle of tilt plane, in degree", + "d": 0.0, + }, + ], + [ + "includepattern", + { + "sec": "Beamline", + "header": "n", + "config": "f", + "l": "Include", + "s": "ipattern", + "h": "file name pattern for included files", + "n": "*", + "d": ["*.tif"], + }, + ], + [ + "excludepattern", + { + "sec": "Beamline", + "header": "n", + "config": "f", + "l": "Exclude", + "s": "epattern", + "h": "file name pattern for excluded files", + "n": "*", + "d": ["*.dark.tif", "*.raw.tif"], + }, + ], + [ + "fliphorizontal", + { + "sec": "Beamline", + "header": "n", + "config": "f", + "l": "Filp horizontally", + "h": "filp the image horizontally", + "n": "?", + "co": True, + "d": False, + }, + ], + [ + "maskedges", + { + "sec": "Others", + "config": "f", + "tt": "array", + "l": "Mask edges", + "h": "mask the edge pixels, first four means the number of pixels masked in each edge \ + (left, right, top, bottom), the last one is the radius of a region masked around the corner", + "n": 5, + "d": [10, 10, 10, 10, 100], + }, + ], + ] + + # default config file path and name + _defaultdata = { + "configfile": ["config.cfg"], + "headertitle": "Configuration information", + } + def __init__(self, filename=None, args=None, **kwargs): - ''' - init the class and update the values of options if specified in - filename/args/kwargs - + """Init the class and update the values of options if specified + in filename/args/kwargs. + it will: 1. init class using HasTraits 2. call self._preInit method @@ -203,56 +295,56 @@ def __init__(self, filename=None, args=None, **kwargs): 4. update the options value using filename/args/kwargs file > args > kwargs 5. call self._postInitTraits() - + :param filename: str, file name of the config file :param args: list of str, args passed from cmd :param kwargs: dict, optional kwargs - + :return: None - ''' + """ HasTraits.__init__(self) ConfigBase.__init__(self, filename, args, **kwargs) - + self._postInitTraits() return - + def _postInitTraits(self): - ''' - additional init process called after traits init - ''' + """Additional init process called after traits init.""" return - + @classmethod def _addOptSelfC(cls, optname, optdata): - ''' - class method, assign options value to *self.option*, using metadata, - this one will create traits objects for each option - + """Class method, assign options value to *self.option*, using + metadata, this one will create traits objects for each option. + :param optname: string, name of the option - :param optdata: dict, metadata of the options, get it from self._optdatalist - ''' - #value type + :param optdata: dict, metadata of the options, get it from + self._optdatalist + """ + # value type vtype = cls._getTypeStrC(optname) - ttype = optdata.get('tt', vtype) + ttype = optdata.get("tt", vtype) ttype = cls._traitstypedict[ttype] - kwargs = {'label':optdata['l'] if 'l' in optdata else optname, - 'desc':optdata['h'], - } - args = [optdata['d']] - if 'c' in optdata: + kwargs = { + "label": optdata["l"] if "l" in optdata else optname, + "desc": optdata["h"], + } + args = [optdata["d"]] + if "c" in optdata: ttype = Enum - args = [optdata['c']] - kwargs['value']=optdata['d'] + args = [optdata["c"]] + kwargs["value"] = optdata["d"] if ttype == Array: args = [] - kwargs['value']=optdata['d'] + kwargs["value"] = optdata["d"] obj = ttype(*args, **kwargs) cls.add_class_trait(optname, obj) return -#ConfigBaseTraits.initConfigClass() -if __name__=='__main__': - test = ConfigBaseTraits(filename='temp.cfg') +# ConfigBaseTraits.initConfigClass() + +if __name__ == "__main__": + test = ConfigBaseTraits(filename="temp.cfg") test.updateConfig() test.configure_traits() diff --git a/src/diffpy/srxconfutils/gitarchive.cfg b/src/diffpy/srxconfutils/gitarchive.cfg index 2f8fb70..43b349f 100644 --- a/src/diffpy/srxconfutils/gitarchive.cfg +++ b/src/diffpy/srxconfutils/gitarchive.cfg @@ -2,4 +2,4 @@ commit = $Format:%H$ date = $Format:%ai$ timestamp = $Format:%at$ -refnames = $Format:%D$ \ No newline at end of file +refnames = $Format:%D$ diff --git a/src/diffpy/srxconfutils/tools.py b/src/diffpy/srxconfutils/tools.py index 26fa5e2..b64baa0 100644 --- a/src/diffpy/srxconfutils/tools.py +++ b/src/diffpy/srxconfutils/tools.py @@ -12,115 +12,125 @@ # ############################################################################## -import numpy as np +import hashlib import re import time import zlib -import hashlib from pkgutil import iter_modules +import numpy as np + + def module_exists(module_name): return module_name in [tuple_[1] for tuple_ in iter_modules()] + def module_exists_lower(module_name): - return module_name.lower() in [tuple_[1].lower() for tuple_ in iter_modules()] + return module_name.lower() in [ + tuple_[1].lower() for tuple_ in iter_modules() + ] + def _configPropertyRad(nm): - ''' - helper function of options delegation, rad to degree - ''' - rv = property(fget=lambda self: np.radians(getattr(self, nm)), - fset=lambda self, val: setattr(self, nm, np.degrees(val)), - fdel=lambda self: delattr(self, nm)) + """Helper function of options delegation, rad to degree.""" + rv = property( + fget=lambda self: np.radians(getattr(self, nm)), + fset=lambda self, val: setattr(self, nm, np.degrees(val)), + fdel=lambda self: delattr(self, nm), + ) return rv + def _configPropertyR(name): - ''' - Create a property that forwards self.name to self.config.name. - + """Create a property that forwards self.name to self.config.name. + read only - ''' - rv = property(fget=lambda self: getattr(self.config, name), - doc='attribute forwarded to self.config, read-only') + """ + rv = property( + fget=lambda self: getattr(self.config, name), + doc="attribute forwarded to self.config, read-only", + ) return rv + def _configPropertyRW(name): - ''' - Create a property that forwards self.name to self.config.name. - + """Create a property that forwards self.name to self.config.name. + read and write - ''' - rv = property(fget=lambda self: getattr(self.config, nm), - fset=lambda self, value: setattr(self.config, nm, value), - fdel=lambda self: delattr(self, nm), - doc='attribute forwarded to self.config, read/write') + """ + rv = property( + fget=lambda self: getattr(self.config, nm), + fset=lambda self, value: setattr(self.config, nm, value), + fdel=lambda self: delattr(self, nm), + doc="attribute forwarded to self.config, read/write", + ) return rv + def str2bool(v): - ''' - turn string to bool - ''' + """Turn string to bool.""" return v.lower() in ("yes", "true", "t", "1") + def opt2Str(opttype, optvalue): - ''' - turn the value of one option to string, according to the option type - list of values are truned into "value1, value2, value3..." - - :param opttype: string, type of opitons, for example 'str' or 'intlist' + """Turn the value of one option to string, according to the option + type list of values are truned into "value1, value2, value3...". + + :param opttype: string, type of opitons, for example 'str' or + 'intlist' :param optvalue: value of the option - :return: string, usually stored in ConfigBase.config - ''' + """ - if opttype.endswith('list'): - rv = ', '.join(map(str, optvalue)) + if opttype.endswith("list"): + rv = ", ".join(map(str, optvalue)) else: rv = str(optvalue) return rv + def StrConv(opttype): - ''' - get the type (or converter function) according to the opttype - - the function doesn't take list - ''' - if opttype.startswith('str'): + """Get the type (or converter function) according to the opttype. + + the function doesn't take list + """ + if opttype.startswith("str"): conv = str - elif opttype.startswith('int'): + elif opttype.startswith("int"): conv = int - elif opttype.startswith('float'): + elif opttype.startswith("float"): conv = float - elif opttype.startswith('bool'): + elif opttype.startswith("bool"): conv = str2bool else: conv = None return conv + def str2Opt(opttype, optvalue): - ''' - convert the string to value of one option, according to the option type - - :param opttype: string, type of opitons, for example 'str' or 'intlist' + """Convert the string to value of one option, according to the + option type. + + :param opttype: string, type of opitons, for example 'str' or + 'intlist' :param optvalue: string, value of the option - :return: value of the option, usually stored in ConfigBase.config - ''' + """ # base converter conv = StrConv(opttype) - if opttype.endswith('list'): - temp = re.split('\s*,\s*', optvalue) + if opttype.endswith("list"): + temp = re.split("\s*,\s*", optvalue) rv = list(map(conv, temp)) if len(temp) > 0 else [] else: rv = conv(optvalue) return rv + class FakeConfigFile(object): - ''' - A fake configfile object used in reading config from header of data - or a real config file. - ''' - def __init__(self, configfile, endline='###'): + """A fake configfile object used in reading config from header of + data or a real config file.""" + + def __init__(self, configfile, endline="###"): self.configfile = configfile self.fp = open(configfile) self.endline = endline @@ -129,45 +139,40 @@ def __init__(self, configfile, endline='###'): return def readline(self): - ''' - readline function - ''' + """Readline function.""" line = self.fp.readline() if line.startswith(self.endline) or self.ended: - rv = '' + rv = "" self.ended = True else: rv = line return rv def close(self): - ''' - close the file - ''' + """Close the file.""" self.fp.close() return - + def __iter__(self): return self - + def __next__(self): line = self.readline() - if line == '': + if line == "": raise StopIteration return line + def checkCRC32(filename): - ''' - calculate the crc32 value of file - + """Calculate the crc32 value of file. + :param filename: path to the file - :return: crc32 value of file - ''' + """ try: - fd = open(filename, 'rb') + fd = open(filename, "rb") except: - return 'Read error' + return "Read error" eachLine = fd.readline() prev = 0 while eachLine: @@ -176,18 +181,17 @@ def checkCRC32(filename): fd.close() return prev + def checkMD5(filename, blocksize=65536): - ''' - calculate the MD5 value of file - + """Calculate the MD5 value of file. + :param filename: path to the file - :return: md5 value of file - ''' + """ try: - fd = open(filename, 'rb') + fd = open(filename, "rb") except: - return 'Read error' + return "Read error" buf = fd.read(blocksize) md5 = hashlib.md5() while len(buf) > 0: @@ -196,14 +200,14 @@ def checkMD5(filename, blocksize=65536): fd.close() return md5.hexdigest() + def checkFileVal(filename): - ''' - check file integrity using crc32 and md5. It will read file twice then - compare the crc32 and md5. If two results doesn't match, it will wait until - the file is completed written to disk. - + """Check file integrity using crc32 and md5. It will read file twice + then compare the crc32 and md5. If two results doesn't match, it + will wait until the file is completed written to disk. + :param filename: path to the file - ''' + """ valflag = False lastcrc = checkCRC32(filename) while not valflag: diff --git a/src/diffpy/srxconfutils/version.py b/src/diffpy/srxconfutils/version.py index 4f60568..45736e1 100644 --- a/src/diffpy/srxconfutils/version.py +++ b/src/diffpy/srxconfutils/version.py @@ -11,17 +11,17 @@ # See LICENSENOTICE.txt for license information. # ############################################################################## - -"""Definition of __version__ and __date__ for this package. -""" +"""Definition of __version__ and __date__ for this package.""" # obtain version information from pkg_resources import get_distribution -_pkgname = __name__.rsplit('.', 1)[0] + +_pkgname = __name__.rsplit(".", 1)[0] __version__ = get_distribution(_pkgname).version # we assume that tag_date was used and __version__ ends in YYYYMMDD -__date__ = __version__[-8:-4] + '-' + \ - __version__[-4:-2] + '-' + __version__[-2:] +__date__ = ( + __version__[-8:-4] + "-" + __version__[-4:-2] + "-" + __version__[-2:] +) # End of file