diff --git a/datastock/_class2.py b/datastock/_class2.py index 8d08e05..44d7fd9 100644 --- a/datastock/_class2.py +++ b/datastock/_class2.py @@ -629,7 +629,7 @@ def connect(self): v0['handle'].parent(), ) except Exception as err: - error = err + error = "1\n" + str(err) elif hasattr(v0['handle'], 'parent'): try: v0['handle'].manager.toolbar.__init__( @@ -637,9 +637,12 @@ def connect(self): v0['handle'].parent(), ) except Exception as err: - error = True + if "can't initialize an object twice" in str(err): + pass + else: + error = "2\n" + str(err) else: - error = True + error = "3" if error is not False: import platform @@ -648,6 +651,7 @@ def connect(self): lstr0 = [f"\t- {k1}" for k1 in dir(v0['handle'])] lstr1 = [f"\t- {k1}" for k1 in dir(v0['handle'].manager.toolbar)] msg = ( + "Problem with connect()\n" f"platform: {platform.platform()}\n" f"python: {sys.version}\n" f"backend: {plt.get_backend()}\n" @@ -657,7 +661,7 @@ def connect(self): + "\n".join(lstr1) ) if error is not True: - msg += '\n' + str(err) + msg += '\n' + str(error) warnings.warn(msg) self._dobj['canvas'][k0]['cid'] = { @@ -1393,4 +1397,4 @@ def on_close(self, event): __all__ = [ sorted([k0 for k0 in locals() if k0.startswith('DataStock')])[-1] -] \ No newline at end of file +] diff --git a/datastock/_generic_check.py b/datastock/_generic_check.py index 7e4716c..035da81 100644 --- a/datastock/_generic_check.py +++ b/datastock/_generic_check.py @@ -362,8 +362,6 @@ def _check_dict_valid_keys( var[k0] = None continue - vv = var.get(k0) - # routine to call if any([ss in v0.keys() for ss in lkarray]): var[k0] = _check_flat1darray( @@ -610,7 +608,7 @@ def _check_all_broadcastable( ndim = lndim[0] else: - lstr = [f"-t {k0}: {v0}" for k0, v0 in dndim.items()] + lstr = [f"\t- {k0}: {v0}" for k0, v0 in dndim.items()] msg = ( "Some keyword args have non-compatible dimensions:\n" + "\n".join(lstr) @@ -675,48 +673,6 @@ def _check_all_broadcastable( # Utilities for plotting # ############################################################################# -# DEPRECATED -# def _check_inplace(coll=None, keys=None): - # """ Check key to data and inplace """ - - # # ----------------------------- - # # keys of data to be extracted - # # ---------------------------- - - # if isinstance(keys, str): - # keys = [keys] - # keys = _check_var_iter( - # keys, 'keys', - # default=None, - # types=list, - # types_iter=str, - # allowed=list(coll.ddata.keys()), - # ) - - # # ---------------------- - # # extract sub-collection - # # ---------------------- - - # lk0 = list(keys) - # for key in keys: - - # # Include all data matching any single ref - # for rr in coll._ddata[key]['ref']: - # for k0, v0 in coll._ddata.items(): - # if v0['ref'] == (rr,): - # if k0 not in lk0: - # lk0.append(k0) - - # # include all data matching all refs - # for k0, v0 in coll._ddata.items(): - # if v0['ref'] == coll._ddata[key]['ref']: - # if k0 not in lk0: - # lk0.append(k0) - - # coll2 = coll.extract(lk0) - - # return keys, coll2 - def _check_dax(dax=None, main=None): @@ -844,7 +800,7 @@ def _check_lim(lim): if len(dfail) > 0: lstr = [f"\t- lim[{ii}]: {vv}" for ii, vv in dfail.items()] msg = ( - "The following non-conformities in lim have been identified:\n"* + "The following non-conformities in lim have been identified:\n" + "\n".join(lstr) ) raise Exception(msg) @@ -900,7 +856,6 @@ def _apply_lim(lim=None, data=None, logic=None): return ind - def _apply_dlim(dlim=None, logic_intervals=None, logic=None, ddata=None): # ------------ @@ -960,6 +915,7 @@ def _apply_dlim(dlim=None, logic_intervals=None, logic=None, ddata=None): lstr = [f"\t- {k0}: {v0}" for k0, v0 in dfail.items()] msg = ( "The following keys have non-compatible shapes:\n" + + "\n".join(lstr) ) raise Exception(msg) @@ -1021,11 +977,6 @@ def _apply_dlim(dlim=None, logic_intervals=None, logic=None, ddata=None): def _check_cmap_vminvmax(data=None, cmap=None, vmin=None, vmax=None): # cmap - c0 = ( - cmap is None - or vmin is None - or vmax is None - ) if cmap is None or vmin is None or vmax is None: nanmax = np.nanmax(data) nanmin = np.nanmin(data) diff --git a/datastock/version.py b/datastock/version.py index c59cfb2..789edb9 100644 --- a/datastock/version.py +++ b/datastock/version.py @@ -1,2 +1,2 @@ # Do not edit, pipeline versioning governed by git tags! -__version__ = '0.0.47' +__version__ = '0.0.49' diff --git a/pyproject.toml b/pyproject.toml index ea97b8e..778b1c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,64 @@ +[project] +name = "datastock" +license = {file = "LICENSE"} +dynamic = ["version"] +description = "Generic handler for multiple heterogenous numpy arrays and subclasses" +readme = "README.md" +requires-python = ">=3.6" +authors = [ + {name = "Didier VEZINET", email = "didier.vezinet@gmail.com"}, +] +maintainers = [ + {name = "Didier VEZINET", email = "didier.vezinet@gmail.com"}, +] +keywords = ["data", "analysis", "interactive", "heterogeneous arrays", "numpy", "Collection"] +classifiers = [ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + "Development Status :: 5 - Production/Stable", + + # Indicate who your project is intended for + "Intended Audience :: Science/Research", + + # Specify the Python versions you support here. + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +dependencies = [ + "numpy", + "scipy", + "matplotlib", + "astropy", +] + + [build-system] -requires = ["setuptools>=40.8.0", - "wheel", - ] +requires = [ + "setuptools>=40.8.0, <64", + "wheel", + "Cython>=0.26", + "numpy", +] + +[dependency-groups] +dev = [ + "pytest", +] + +[project.optional-dependencies] +linting = [ + 'ruff' +] +formatting = [ + 'ruff' +] + +[project.entry-points."datastock"] +datastock = "scripts.main:main" diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/_bash_version.py b/scripts/_bash_version.py new file mode 100755 index 0000000..e23a534 --- /dev/null +++ b/scripts/_bash_version.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +# Built-in +import os + + +################################################### +################################################### +# DEFAULTS +################################################### + + +_PATH_HERE = os.path.dirname(__file__) + + +################################################### +################################################### +# function +################################################### + + +def main( + verb=None, + envvar=None, + path=None, + warn=None, + force=None, + ddef=None, +): + """ Print version """ + + # -------------- + # Check inputs + # -------------- + + kwd = locals() + for k0 in set(ddef.keys()).intersection(kwd.keys()): + if kwd[k0] is None: + kwd[k0] = ddef[k0] + verb, path = kwd['verb'], kwd['path'] + + # verb, warn, force + dbool = {'verb': verb} + for k0, v0 in dbool.items(): + if v0 is None: + dbool[k0] = ddef[k0] + if not isinstance(dbool[k0], bool): + msg = ( + f"Arg '{k0}' must be a bool\n" + f"\t- provided: {dbool[k0]}\n" + ) + raise Exception(msg) + + # -------------- + # Fetch version from git tags, and write to version.py + # Also, when git is not available (PyPi package), use stored version.py + + pfe = os.path.join(path, 'version.py') + if not os.path.isfile(pfe): + msg = ( + "It seems your current install has no version.py:\n" + f"\t- looked for: {pfe}" + ) + raise Exception(msg) + + # -------------- + # Read file + + with open(pfe, 'r') as fh: + version = fh.read().strip().split("=")[-1].replace("'", '') + version = version.lower().replace('v', '').replace(' ', '') + + # -------------- + # Outputs + + if dbool['verb'] is True: + print(version) diff --git a/scripts/_dparser.py b/scripts/_dparser.py new file mode 100644 index 0000000..01e98a3 --- /dev/null +++ b/scripts/_dparser.py @@ -0,0 +1,109 @@ +import sys +import os +import getpass +import argparse + + +# test if in a git repo +_HERE = os.path.abspath(os.path.dirname(__file__)) +_REPOPATH = os.path.dirname(_HERE) +_REPO_NAME = 'datastock' + + +# ############################################################################# +# utility functions +# ############################################################################# + + +def _str2bool(v): + if isinstance(v, bool): + return v + elif v.lower() in ['yes', 'true', 'y', 't', '1']: + return True + elif v.lower() in ['no', 'false', 'n', 'f', '0']: + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected!') + + +def _str2boolstr(v): + if isinstance(v, bool): + return v + elif isinstance(v, str): + if v.lower() in ['yes', 'true', 'y', 't', '1']: + return True + elif v.lower() in ['no', 'false', 'n', 'f', '0']: + return False + elif v.lower() == 'none': + return None + else: + return v + else: + raise argparse.ArgumentTypeError('Boolean, None or str expected!') + + +def _str2tlim(v): + c0 = (v.isdigit() + or ('.' in v + and len(v.split('.')) == 2 + and all([vv.isdigit() for vv in v.split('.')]))) + if c0 is True: + v = float(v) + elif v.lower() == 'none': + v = None + return v + + +# ############################################################################# +# Parser for version +# ############################################################################# + + +def parser_version(): + msg = f""" Get {_REPO_NAME} version from bash + + If run from a git repo containing {_REPO_NAME}, just returns git describe + Otherwise reads the version stored in {_REPO_NAME}/version.py + + """ + ddef = { + 'path': os.path.join(_REPOPATH, _REPO_NAME), + 'envvar': False, + 'verb': True, + 'warn': True, + 'force': False, + 'name': f'{_REPO_NAME.upper()}_VERSION', + } + + # Instanciate parser + parser = argparse.ArgumentParser(description=msg) + + # optional path + parser.add_argument( + '-p', '--path', + type=str, + help='source directory where version.py is found', + required=False, + default=ddef['path'], + ) + + # verb + parser.add_argument( + '-v', '--verb', + type=_str2bool, + help='flag indicating whether to print the version', + required=False, + default=ddef['verb'], + ) + + return ddef, parser + + +# ############################################################################# +# Parser dict +# ############################################################################# + + +_DPARSER = { + 'version': parser_version, +} diff --git a/scripts/main.py b/scripts/main.py new file mode 100755 index 0000000..cad6f8f --- /dev/null +++ b/scripts/main.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python + +# Built-in +import sys +import os +import argparse + + +# import parser dicti +from . import _dparser +from . import _bash_version + + +################################################### +################################################### +# default values +################################################### + + +_PATH_HERE = os.path.abspath(os.path.dirname(__file__)) + + +_LOPTIONS = ['--version'] +_LOPSTRIP = [ss.strip('--') for ss in _LOPTIONS] + + +################################################### +################################################### +# function +################################################### + + +def datastock_bash(option=None, ddef=None, **kwdargs): + """ Print tofu version and / or store in environment variable """ + + # -------------- + # Check inputs + # -------------- + + if option not in _LOPSTRIP: + msg = ( + "Provided option is not acceptable:\n" + f"\t- available: {_LOPSTRIP}\n" + f"\t- provided: {option}" + ) + raise Exception(msg) + + # -------------- + # call corresponding bash command + # -------------- + + if option == 'version': + _bash_version.main( + ddef=ddef, + **kwdargs, + ) + + +################################################### +################################################### +# main +################################################### + + +def main(): + # Parse input arguments + msg = """ Get tofu version from bash optionally set an enviroment variable + + If run from a git repo containing tofu, simply returns git describe + Otherwise reads the tofu version stored in tofu/version.py + + """ + + # ------------------ + # Instanciate parser + # ------------------ + + parser = argparse.ArgumentParser(description=msg) + + # --------------------- + # which script to call + # --------------------- + + parser.add_argument( + 'option', + nargs='?', + type=str, + default='None', + ) + + # + parser.add_argument( + '-v', '--version', + help='get tofu current version', + required=False, + action='store_true', + ) + + # Others + # parser.add_argument('kwd', nargs='?', type=str, default='None') + + # ------------------- + # check options + # ------------------- + + if sys.argv[1] not in _LOPTIONS: + msg = ( + "Provided option is not acceptable:\n" + f"\t- available: {_LOPTIONS}\n" + f"\t- provided: {sys.argv[1]}\n" + ) + raise Exception(msg) + + if len(sys.argv) > 2: + if any([ss in sys.argv[2:] for ss in _LOPTIONS]): + lopt = [ss for ss in sys.argv[1:] if ss in _LOPTIONS] + msg = ( + "Only one option can be provided!\n" + f"\t- provided: {lopt}" + ) + raise Exception(msg) + + # ---------------------- + # def values and parser + # ---------------------- + + option = sys.argv[1].strip('--') + ddef, parser = _dparser._DPARSER[option]() + if len(sys.argv) > 2: + kwdargs = dict(parser.parse_args(sys.argv[2:])._get_kwargs()) + else: + kwdargs = {} + + # ---------------------- + # Call function + # ---------------------- + + datastock_bash(option=option, ddef=ddef, **kwdargs) + + +################################################### +################################################### +# __main__ +################################################### + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index eb3bab2..9efa067 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,6 @@ # Built-in import os -import subprocess from codecs import open # ... setup tools from setuptools import setup, find_packages @@ -16,7 +15,7 @@ import _updateversion as up -# == Getting version ===================================================== +# == Getting version =========================================== _HERE = os.path.abspath(os.path.dirname(__file__)) version = up.updateversion() @@ -26,7 +25,7 @@ print("") -# ============================================================================= +# ============================================================== # Get the long description from the README file # Get the readme file whatever its extension (md vs rst) @@ -45,10 +44,10 @@ long_description_content_type = "text/x-rst" -# ============================================================================= +# ============================================================= -# ============================================================================= +# ============================================================== # Compiling files setup( @@ -167,7 +166,12 @@ # Theye are generally preferable over scripts because they provide # cross-platform support and allow pip to create the appropriate form # of executable for the target platform. - # entry_points={}, + entry_points={ + 'console_scripts': [ + 'datastock=scripts.main:main', + ], + }, + # include_dirs=[np.get_include()], py_modules=['_updateversion'],