From 9399285bbafd3663ae690c1d811d177f3d86090b Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Wed, 26 Oct 2022 11:42:59 -0400 Subject: [PATCH 1/8] move build configuration to `pyproject.toml` --- .flake8 | 5 +++++ pyproject.toml | 50 +++++++++++++++++++++++++++++++++++++++++++++-- setup.cfg | 53 -------------------------------------------------- setup.py | 29 +++++++++++++-------------- 4 files changed, 66 insertions(+), 71 deletions(-) create mode 100644 .flake8 delete mode 100644 setup.cfg diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..c27c42e --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +# flake8 does not support pyproject.toml (https://github.com/PyCQA/flake8/issues/234) + +[flake8] +select = E101,E111,E112,E113,E101,E111,E112,E113,E201,E202,E203,E211,E221,E222,E223,E224,E225,E226,E227,E228,E231,E241,E242,E251,E271,E272,E273,E274,E901,E902,W191,W291,W292,W293,W391 +exclude = extern,sphinx,*parsetab.py,build \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 99bbf16..261cac8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,56 @@ +[project] +name = 'stsci.imagestats' +description = 'Compute sigma-clipped statistics on data arrays' +readme = 'README.md' +requires-python = '>=3.6' +license = { file = 'LICENSE' } +authors = [{ name = 'Warren Hack', email = 'help@stsci.edu' }, { name = 'Christopher Hanley' }] +classifiers = [ + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering :: Astronomy', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Development Status :: 7 - Inactive', +] +dependencies = [ + 'numpy>=1.14', +] +dynamic = ['version'] + +[project.optional-dependencies] +docs = [ + 'numpydoc', + 'sphinx', + 'sphinx-automodapi', + 'sphinx-rtd-theme', + 'stsci-rtd-theme', + 'tomli; python_version <"3.11"', +] + +[project.urls] +'Tracker' = 'https://github.com/spacetelescope/stsci.imagestats/issues' +'Documentation' = 'https://stsciimagestats.readthedocs.io/en/stable/' +'Source Code' = 'https://github.com/spacetelescope/stsci.imagestats' + [build-system] requires = [ - "setuptools>=38.2.5", - "setuptools_scm", + "setuptools >=61", + "setuptools_scm[toml] >=3.4", "wheel", "oldest-supported-numpy", ] build-backend = "setuptools.build_meta" [tool.setuptools_scm] +write_to = "stsci/imagestats/_version.py" + +[tool.setuptools] +zip-safe = false + +[tool.setuptools.packages.find] +include = ['stsci'] + +[tool.setuptools.package-data] +'*' = ['README.md', 'LICENSE.txt'] \ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index b16bc21..0000000 --- a/setup.cfg +++ /dev/null @@ -1,53 +0,0 @@ -[metadata] -name = stsci.imagestats -description = Compute sigma-clipped statistics on data arrays -long_description = file: README.rst -long_description_content_type = text/x-rst -author = Warren Hack, Christopher Hanley -author_email = help@stsci.edu -license = BSD-3-Clause -url = https://github.com/spacetelescope/stsci.imagestats -project_urls = - Tracker = https://github.com/spacetelescope/stsci.imagestats/issues - Documentation = https://stsciimagestats.readthedocs.io/en/stable/ - Source Code = https://github.com/spacetelescope/stsci.imagestats -classifiers= - Intended Audience :: Science/Research - License :: OSI Approved :: BSD License - Operating System :: OS Independent - Programming Language :: Python - Topic :: Scientific/Engineering :: Astronomy - Topic :: Software Development :: Libraries :: Python Modules - Development Status :: 7 - Inactive - -[options] -zip_safe = False -python_requires = >=3.6 -setup_requires = - setuptools_scm -install_requires = - numpy>=1.14 -packages = find: -namespace_packages = - stsci - -[options.extras_require] -docs = - numpydoc - sphinx - sphinx-automodapi - sphinx-rtd-theme - stsci-rtd-theme - -[build-sphinx] -source-dir=docs -build-dir=docs -all_files=1 - -[upload_docs] -upload-dir=docs/_build/html -show-response=1 - -[pep8] -select=E101,W191,W291,W292,W293,W391,E111,E112,E113,E901,E902,E101,W191,W291,W292,W293,W391,E111,E112,E113,E901,E902,E201,E202,E203,E211,E221,E222,E223,E224,E225,E226,E227,E228,E231,E241,E242,E251,E271,E272,E273,E274 -exclude=extern,sphinx,*parsetab.py diff --git a/setup.py b/setup.py index 2f68203..b9e5826 100755 --- a/setup.py +++ b/setup.py @@ -1,8 +1,8 @@ #!/usr/bin/env python -import numpy import sys -from setuptools import setup, find_packages, Extension +import numpy +from setuptools import setup, Extension # Setup C module include directories include_dirs = [numpy.get_include()] @@ -17,20 +17,17 @@ ('__STDC__', 1) ] -PACKAGE_DATA = {'': ['README.md', 'LICENSE.txt']} +ext_modules = [ + Extension('stsci.imagestats.buildHistogram', + ['src/buildHistogram.c'], + include_dirs=include_dirs, + define_macros=define_macros), + Extension('stsci.imagestats.computeMean', + ['src/computeMean.c'], + include_dirs=include_dirs, + define_macros=define_macros), +] setup( - use_scm_version={"write_to": "stsci/imagestats/_version.py"}, - setup_requires=['setuptools_scm'], - package_data=PACKAGE_DATA, - ext_modules=[ - Extension('stsci.imagestats.buildHistogram', - ['src/buildHistogram.c'], - include_dirs=include_dirs, - define_macros=define_macros), - Extension('stsci.imagestats.computeMean', - ['src/computeMean.c'], - include_dirs=include_dirs, - define_macros=define_macros), - ], + ext_modules=ext_modules, ) From 5cc6b168ccefd67b43713a7895499bdaf5f3efb3 Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Wed, 26 Oct 2022 11:43:23 -0400 Subject: [PATCH 2/8] format for `flake8` --- docs/exts/numfig.py | 11 +++-- stsci/imagestats/__init__.py | 82 +++++++++++++++++---------------- stsci/imagestats/histogram1d.py | 7 ++- 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/docs/exts/numfig.py b/docs/exts/numfig.py index 4659649..b062583 100644 --- a/docs/exts/numfig.py +++ b/docs/exts/numfig.py @@ -1,6 +1,6 @@ # Downloaded from https://bitbucket.org/arjones6/sphinx-numfig -from docutils.nodes import figure, caption, Text, reference, raw, SkipNode, Element +from docutils.nodes import figure, caption, Text, reference, raw, SkipNode from sphinx.roles import XRefRole @@ -9,6 +9,7 @@ class page_ref(reference): pass + class num_ref(reference): pass @@ -18,10 +19,12 @@ class num_ref(reference): def skip_page_ref(self, node): raise SkipNode + def latex_visit_page_ref(self, node): self.body.append("\\pageref{%s:%s}" % (node['refdoc'], node['reftarget'])) raise SkipNode + def latex_visit_num_ref(self, node): fields = node['reftarget'].split('#') if len(fields) > 1: @@ -61,7 +64,6 @@ def doctree_resolved(app, doctree, docname): i += 1 - # replace numfig nodes with links if app.builder.name != 'latex': for ref_info in doctree.traverse(num_ref): @@ -79,16 +81,17 @@ def doctree_resolved(app, doctree, docname): target_doc = app.builder.env.figid_docname_map[target] link = "%s#%s" % (app.builder.get_relative_uri(docname, target_doc), target) - html = '%s' % (link, labelfmt %(figids[target])) + html = '%s' % (link, labelfmt % (figids[target])) ref_info.replace_self(raw(html, html, format='html')) else: ref_info.replace_self(Text(labelfmt % (figids[target]))) def clean_env(app): - app.builder.env.i=1 + app.builder.env.i = 1 app.builder.env.figid_docname_map = {} + def setup(app): app.add_config_value('number_figures', True, True) app.add_config_value('figure_caption_prefix', "Figure", True) diff --git a/stsci/imagestats/__init__.py b/stsci/imagestats/__init__.py index 714fc91..939041b 100644 --- a/stsci/imagestats/__init__.py +++ b/stsci/imagestats/__init__.py @@ -7,11 +7,15 @@ :License: :doc:`../LICENSE` """ + import time + import numpy as np -from .histogram1d import histogram1d -from .computeMean import computeMean + from ._version import version as __version__ +from .computeMean import computeMean +from .histogram1d import histogram1d + class ImageStats: """ @@ -110,15 +114,16 @@ class ImageStats: datatype. """ + def __init__(self, image, fields="npix,min,max,mean,stddev", lower=None, upper=None, nclip=0, lsig=3.0, usig=3.0, binwidth=0.1): - #Initialize the start time of the program + # Initialize the start time of the program self.startTime = time.time() # Input Value if image.dtype > np.float32: - #Warning: Input array is being downcast to a float32 array + # Warning: Input array is being downcast to a float32 array image = image.astype(np.float32) if nclip < 0: @@ -146,7 +151,7 @@ def __init__(self, image, fields="npix,min,max,mean,stddev", self.mean = None self.mode = None self.bins = None - self.median = None # numpy computed median with clipping + self.median = None # numpy computed median with clipping self.midpt = None # IRAF-based pseudo-median using bins # Compute Global minimum and maximum @@ -185,7 +190,7 @@ def __init__(self, image, fields="npix,min,max,mean,stddev", self.deltaTime = self.stopTime - self.startTime def _error_no_valid_pixels(self, clipiter, minval, maxval, minclip, maxclip): - errormsg = "\n##############################################\n" + errormsg = "\n##############################################\n" errormsg += "# #\n" errormsg += "# ERROR: #\n" errormsg += "# Unable to compute image statistics. No #\n" @@ -210,11 +215,10 @@ def _computeStats(self): _clipmax = self.upper # Compute the clipped mean iterating the user specified numer of iterations - for iter in range(self.nclip+1): - + for iter in range(self.nclip + 1): try: - _npix,_mean,_stddev,_min,_max = computeMean(self.image,_clipmin,_clipmax) - #print("_npix,_mean,_stddev,_min,_max = ",_npix,_mean,_stddev,_min,_max) + _npix, _mean, _stddev, _min, _max = computeMean(self.image, _clipmin, _clipmax) + # print("_npix,_mean,_stddev,_min,_max = ",_npix,_mean,_stddev,_min,_max) except: raise SystemError("An error processing the array object information occured in \ the computeMean module of imagestats.") @@ -244,18 +248,18 @@ def _computeStats(self): # clean-up intermediate product since it is no longer needed del _image - if ( (self.fields.find('mode') != -1) or (self.fields.find('midpt') != -1) ): + if ((self.fields.find('mode') != -1) or (self.fields.find('midpt') != -1)): # Populate the historgram _hwidth = self.binwidth * _stddev _drange = _max - _min _minfloatval = 10.0 * np.finfo(dtype=np.float32).eps if _hwidth < _minfloatval or abs(_drange) < _minfloatval or \ - _hwidth > _drange: + _hwidth > _drange: _nbins = 1 _dz = _drange print("! WARNING: Clipped data falls within 1 histogram bin") else: - _nbins = int( (_max - _min) / _hwidth ) + 1 + _nbins = int((_max - _min) / _hwidth) + 1 _dz = float(_max - _min) / float(_nbins - 1) _hist = histogram1d(self.image, _nbins, _dz, _min) @@ -265,12 +269,12 @@ def _computeStats(self): if (self.fields.find('mode') != -1): # Compute the mode, taking into account special cases if _nbins == 1: - _mode = _min + 0.5 *_hwidth + _mode = _min + 0.5 * _hwidth elif _nbins == 2: if _bins[0] > _bins[1]: - _mode = _min + 0.5 *_hwidth + _mode = _min + 0.5 * _hwidth elif _bins[0] < _bins[1]: - _mode = _min + 1.5 *_hwidth + _mode = _min + 1.5 * _hwidth else: _mode = _min + _hwidth else: @@ -287,7 +291,7 @@ def _computeStats(self): if _denom == 0: _mode = _min + (_peakindex + 0.5) * _hwidth else: - _mode = _peakindex + 1 + (0.5 * (int(_dh1) - int(_dh2))/_denom) + _mode = _peakindex + 1 + (0.5 * (int(_dh1) - int(_dh2)) / _denom) _mode = _min + ((_mode - 0.5) * _hwidth) # Return the mode self.mode = _mode @@ -295,30 +299,30 @@ def _computeStats(self): if (self.fields.find('midpt') != -1): # Compute a pseudo-Median Value using IRAF's algorithm _binSum = np.cumsum(_bins).astype(np.float32) - _binSum = _binSum/_binSum[-1] + _binSum = _binSum / _binSum[-1] _lo = np.where(_binSum >= 0.5)[0][0] _hi = _lo + 1 _h1 = _min + _lo * _hwidth if (_lo == 0): - _hdiff = _binSum[_hi-1] + _hdiff = _binSum[_hi - 1] else: - _hdiff = _binSum[_hi-1] - _binSum[_lo-1] + _hdiff = _binSum[_hi - 1] - _binSum[_lo - 1] if (_hdiff == 0): _midpt = _h1 elif (_lo == 0): _midpt = _h1 + 0.5 / _hdiff * _hwidth else: - _midpt = _h1 + (0.5 - _binSum[_lo-1])/_hdiff * _hwidth + _midpt = _h1 + (0.5 - _binSum[_lo - 1]) / _hdiff * _hwidth self.midpt = _midpt # These values will only be returned if the histogram is computed. self.hmin = _min + 0.5 * _hwidth self.hwidth = _hwidth - self.histogram = _bins + self.histogram = _bins - #Return values + # Return values self.stddev = _stddev self.mean = _mean self.npix = _npix @@ -333,19 +337,19 @@ def printStats(self): """ Print the requested statistics values for those fields specified on input. """ print("--- Imagestats Results ---") - if (self.fields.find('npix') != -1 ): - print("Number of pixels : ",self.npix) - if (self.fields.find('min') != -1 ): - print("Minimum value : ",self.min) - if (self.fields.find('max') != -1 ): - print("Maximum value : ",self.max) - if (self.fields.find('stddev') != -1 ): - print("Standard Deviation: ",self.stddev) - if (self.fields.find('mean') != -1 ): - print("Mean : ",self.mean) - if (self.fields.find('mode') != -1 ): - print("Mode : ",self.mode) - if (self.fields.find('median') != -1 ): - print("Median : ",self.median) - if (self.fields.find('midpt') != -1 ): - print("Midpt : ",self.midpt) + if (self.fields.find('npix') != -1): + print("Number of pixels : ", self.npix) + if (self.fields.find('min') != -1): + print("Minimum value : ", self.min) + if (self.fields.find('max') != -1): + print("Maximum value : ", self.max) + if (self.fields.find('stddev') != -1): + print("Standard Deviation: ", self.stddev) + if (self.fields.find('mean') != -1): + print("Mean : ", self.mean) + if (self.fields.find('mode') != -1): + print("Mode : ", self.mode) + if (self.fields.find('median') != -1): + print("Median : ", self.median) + if (self.fields.find('midpt') != -1): + print("Midpt : ", self.midpt) diff --git a/stsci/imagestats/histogram1d.py b/stsci/imagestats/histogram1d.py index 675f23b..a9682a9 100644 --- a/stsci/imagestats/histogram1d.py +++ b/stsci/imagestats/histogram1d.py @@ -7,7 +7,9 @@ :License: :doc:`../LICENSE` """ + import numpy as np + from . import buildHistogram @@ -31,6 +33,7 @@ class histogram1d: Zero value for the histogram range """ + def __init__(self, arrayInput, nbins, binWidth, zeroValue): # Initialize Object Attributes self._data = arrayInput.astype(np.float32) @@ -54,9 +57,9 @@ def __init__(self, arrayInput, nbins, binWidth, zeroValue): def _populateHistogram(self): """Call the C-code that actually populates the histogram""" - try : + try: buildHistogram.populate1DHist(self._data, self.histogram, - self.minValue, self.maxValue, self.binWidth) + self.minValue, self.maxValue, self.binWidth) except: if ((self._data.max() - self._data.min()) < self.binWidth): raise ValueError("In histogram1d class, the binWidth is " From b009310e1033e052f650a96806a93d46ebab1eab Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Wed, 26 Oct 2022 11:45:44 -0400 Subject: [PATCH 3/8] read docs metadata --- docs/source/conf.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 35f8de9..8e2f773 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -14,7 +14,7 @@ import os import sys -import datetime +from datetime import datetime import importlib import sphinx import stsci_rtd_theme @@ -35,8 +35,9 @@ sys.path.insert(0, os.path.abspath('../stsci/imagestats')) # -- General configuration ------------------------------------------------ -conf.read([os.path.join(os.path.dirname(__file__), '../..', 'setup.cfg')]) -setup_cfg = dict(conf.items('metadata')) +with open(Path(__file__).parent.parent.parent / "pyproject.toml", "rb") as configuration_file: + conf = tomli.load(configuration_file) +setup_cfg = conf['project'] # If your documentation needs a minimal Sphinx version, state it here. needs_sphinx = '1.3' @@ -112,8 +113,9 @@ def check_sphinx_version(expected_version): # General information about the project project = setup_cfg['name'] -author = setup_cfg['author'] -copyright = u'{0}, {1}'.format(datetime.datetime.now().year, author) +primary_author = setup_cfg["authors"][0] +author = f'{primary_author["name"]} <{primary_author["email"]}>' +copyright = f'{datetime.now().year}, {primary_author["name"]}' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the From 65ebb7125427786b2376373f208491be11d91dbf Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Mon, 23 Jan 2023 08:30:31 -0500 Subject: [PATCH 4/8] use `peppyproject` --- pyproject.toml | 85 +++++++++++++++++++++++++++++++++----------------- setup.py | 4 +-- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 261cac8..f93dc23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,42 +1,53 @@ [project] -name = 'stsci.imagestats' -description = 'Compute sigma-clipped statistics on data arrays' -readme = 'README.md' -requires-python = '>=3.6' -license = { file = 'LICENSE' } -authors = [{ name = 'Warren Hack', email = 'help@stsci.edu' }, { name = 'Christopher Hanley' }] +name = "stsci.imagestats" +description = "Compute sigma-clipped statistics on data arrays" +requires-python = ">=3.6" +authors = [ + { name = "Warren Hack", email = "help@stsci.edu" }, + { name = "Christopher Hanley" }, +] classifiers = [ - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Scientific/Engineering :: Astronomy', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Development Status :: 7 - Inactive', + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Topic :: Scientific/Engineering :: Astronomy", + "Topic :: Software Development :: Libraries :: Python Modules", + "Development Status :: 7 - Inactive", ] dependencies = [ - 'numpy>=1.14', + "numpy>=1.14", +] +dynamic = [ + "version", ] -dynamic = ['version'] + +[project.readme] +file = "README.rst" +content-type = "text/x-rst" + +[project.license] +file = "LICENSE.txt" +content-type = "text/plain" + +[project.urls] +Homepage = "https://github.com/spacetelescope/stsci.imagestats" +Tracker = "https://github.com/spacetelescope/stsci.imagestats/issues" +Documentation = "https://stsciimagestats.readthedocs.io/en/stable/" +"Source Code" = "https://github.com/spacetelescope/stsci.imagestats" [project.optional-dependencies] docs = [ - 'numpydoc', - 'sphinx', - 'sphinx-automodapi', - 'sphinx-rtd-theme', - 'stsci-rtd-theme', - 'tomli; python_version <"3.11"', + "numpydoc", + "sphinx", + "sphinx-automodapi", + "sphinx-rtd-theme", + "stsci-rtd-theme", ] -[project.urls] -'Tracker' = 'https://github.com/spacetelescope/stsci.imagestats/issues' -'Documentation' = 'https://stsciimagestats.readthedocs.io/en/stable/' -'Source Code' = 'https://github.com/spacetelescope/stsci.imagestats' - [build-system] requires = [ - "setuptools >=61", + "setuptools>=61.2", "setuptools_scm[toml] >=3.4", "wheel", "oldest-supported-numpy", @@ -48,9 +59,25 @@ write_to = "stsci/imagestats/_version.py" [tool.setuptools] zip-safe = false +include-package-data = false +namespace-packages = [ + "stsci", +] [tool.setuptools.packages.find] -include = ['stsci'] +namespaces = false [tool.setuptools.package-data] -'*' = ['README.md', 'LICENSE.txt'] \ No newline at end of file +"*" = [ + "README.md", + "LICENSE.txt", +] + +[tool.build-sphinx] +source-dir = "docs" +build-dir = "docs" +all_files = "1" + +[tool.distutils.upload_docs] +upload-dir = "docs/_build/html" +show-response = 1 diff --git a/setup.py b/setup.py index b9e5826..9f82e54 100755 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -import sys - import numpy +import sys from setuptools import setup, Extension + # Setup C module include directories include_dirs = [numpy.get_include()] From 04bd92088dde896b253eff5ecf57ef883ff1a9d0 Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Mon, 23 Jan 2023 08:32:12 -0500 Subject: [PATCH 5/8] undo formatting --- docs/exts/numfig.py | 11 ++--- stsci/imagestats/__init__.py | 82 ++++++++++++++++----------------- stsci/imagestats/histogram1d.py | 7 +-- 3 files changed, 45 insertions(+), 55 deletions(-) diff --git a/docs/exts/numfig.py b/docs/exts/numfig.py index b062583..4659649 100644 --- a/docs/exts/numfig.py +++ b/docs/exts/numfig.py @@ -1,6 +1,6 @@ # Downloaded from https://bitbucket.org/arjones6/sphinx-numfig -from docutils.nodes import figure, caption, Text, reference, raw, SkipNode +from docutils.nodes import figure, caption, Text, reference, raw, SkipNode, Element from sphinx.roles import XRefRole @@ -9,7 +9,6 @@ class page_ref(reference): pass - class num_ref(reference): pass @@ -19,12 +18,10 @@ class num_ref(reference): def skip_page_ref(self, node): raise SkipNode - def latex_visit_page_ref(self, node): self.body.append("\\pageref{%s:%s}" % (node['refdoc'], node['reftarget'])) raise SkipNode - def latex_visit_num_ref(self, node): fields = node['reftarget'].split('#') if len(fields) > 1: @@ -64,6 +61,7 @@ def doctree_resolved(app, doctree, docname): i += 1 + # replace numfig nodes with links if app.builder.name != 'latex': for ref_info in doctree.traverse(num_ref): @@ -81,17 +79,16 @@ def doctree_resolved(app, doctree, docname): target_doc = app.builder.env.figid_docname_map[target] link = "%s#%s" % (app.builder.get_relative_uri(docname, target_doc), target) - html = '%s' % (link, labelfmt % (figids[target])) + html = '%s' % (link, labelfmt %(figids[target])) ref_info.replace_self(raw(html, html, format='html')) else: ref_info.replace_self(Text(labelfmt % (figids[target]))) def clean_env(app): - app.builder.env.i = 1 + app.builder.env.i=1 app.builder.env.figid_docname_map = {} - def setup(app): app.add_config_value('number_figures', True, True) app.add_config_value('figure_caption_prefix', "Figure", True) diff --git a/stsci/imagestats/__init__.py b/stsci/imagestats/__init__.py index 939041b..714fc91 100644 --- a/stsci/imagestats/__init__.py +++ b/stsci/imagestats/__init__.py @@ -7,15 +7,11 @@ :License: :doc:`../LICENSE` """ - import time - import numpy as np - -from ._version import version as __version__ -from .computeMean import computeMean from .histogram1d import histogram1d - +from .computeMean import computeMean +from ._version import version as __version__ class ImageStats: """ @@ -114,16 +110,15 @@ class ImageStats: datatype. """ - def __init__(self, image, fields="npix,min,max,mean,stddev", lower=None, upper=None, nclip=0, lsig=3.0, usig=3.0, binwidth=0.1): - # Initialize the start time of the program + #Initialize the start time of the program self.startTime = time.time() # Input Value if image.dtype > np.float32: - # Warning: Input array is being downcast to a float32 array + #Warning: Input array is being downcast to a float32 array image = image.astype(np.float32) if nclip < 0: @@ -151,7 +146,7 @@ def __init__(self, image, fields="npix,min,max,mean,stddev", self.mean = None self.mode = None self.bins = None - self.median = None # numpy computed median with clipping + self.median = None # numpy computed median with clipping self.midpt = None # IRAF-based pseudo-median using bins # Compute Global minimum and maximum @@ -190,7 +185,7 @@ def __init__(self, image, fields="npix,min,max,mean,stddev", self.deltaTime = self.stopTime - self.startTime def _error_no_valid_pixels(self, clipiter, minval, maxval, minclip, maxclip): - errormsg = "\n##############################################\n" + errormsg = "\n##############################################\n" errormsg += "# #\n" errormsg += "# ERROR: #\n" errormsg += "# Unable to compute image statistics. No #\n" @@ -215,10 +210,11 @@ def _computeStats(self): _clipmax = self.upper # Compute the clipped mean iterating the user specified numer of iterations - for iter in range(self.nclip + 1): + for iter in range(self.nclip+1): + try: - _npix, _mean, _stddev, _min, _max = computeMean(self.image, _clipmin, _clipmax) - # print("_npix,_mean,_stddev,_min,_max = ",_npix,_mean,_stddev,_min,_max) + _npix,_mean,_stddev,_min,_max = computeMean(self.image,_clipmin,_clipmax) + #print("_npix,_mean,_stddev,_min,_max = ",_npix,_mean,_stddev,_min,_max) except: raise SystemError("An error processing the array object information occured in \ the computeMean module of imagestats.") @@ -248,18 +244,18 @@ def _computeStats(self): # clean-up intermediate product since it is no longer needed del _image - if ((self.fields.find('mode') != -1) or (self.fields.find('midpt') != -1)): + if ( (self.fields.find('mode') != -1) or (self.fields.find('midpt') != -1) ): # Populate the historgram _hwidth = self.binwidth * _stddev _drange = _max - _min _minfloatval = 10.0 * np.finfo(dtype=np.float32).eps if _hwidth < _minfloatval or abs(_drange) < _minfloatval or \ - _hwidth > _drange: + _hwidth > _drange: _nbins = 1 _dz = _drange print("! WARNING: Clipped data falls within 1 histogram bin") else: - _nbins = int((_max - _min) / _hwidth) + 1 + _nbins = int( (_max - _min) / _hwidth ) + 1 _dz = float(_max - _min) / float(_nbins - 1) _hist = histogram1d(self.image, _nbins, _dz, _min) @@ -269,12 +265,12 @@ def _computeStats(self): if (self.fields.find('mode') != -1): # Compute the mode, taking into account special cases if _nbins == 1: - _mode = _min + 0.5 * _hwidth + _mode = _min + 0.5 *_hwidth elif _nbins == 2: if _bins[0] > _bins[1]: - _mode = _min + 0.5 * _hwidth + _mode = _min + 0.5 *_hwidth elif _bins[0] < _bins[1]: - _mode = _min + 1.5 * _hwidth + _mode = _min + 1.5 *_hwidth else: _mode = _min + _hwidth else: @@ -291,7 +287,7 @@ def _computeStats(self): if _denom == 0: _mode = _min + (_peakindex + 0.5) * _hwidth else: - _mode = _peakindex + 1 + (0.5 * (int(_dh1) - int(_dh2)) / _denom) + _mode = _peakindex + 1 + (0.5 * (int(_dh1) - int(_dh2))/_denom) _mode = _min + ((_mode - 0.5) * _hwidth) # Return the mode self.mode = _mode @@ -299,30 +295,30 @@ def _computeStats(self): if (self.fields.find('midpt') != -1): # Compute a pseudo-Median Value using IRAF's algorithm _binSum = np.cumsum(_bins).astype(np.float32) - _binSum = _binSum / _binSum[-1] + _binSum = _binSum/_binSum[-1] _lo = np.where(_binSum >= 0.5)[0][0] _hi = _lo + 1 _h1 = _min + _lo * _hwidth if (_lo == 0): - _hdiff = _binSum[_hi - 1] + _hdiff = _binSum[_hi-1] else: - _hdiff = _binSum[_hi - 1] - _binSum[_lo - 1] + _hdiff = _binSum[_hi-1] - _binSum[_lo-1] if (_hdiff == 0): _midpt = _h1 elif (_lo == 0): _midpt = _h1 + 0.5 / _hdiff * _hwidth else: - _midpt = _h1 + (0.5 - _binSum[_lo - 1]) / _hdiff * _hwidth + _midpt = _h1 + (0.5 - _binSum[_lo-1])/_hdiff * _hwidth self.midpt = _midpt # These values will only be returned if the histogram is computed. self.hmin = _min + 0.5 * _hwidth self.hwidth = _hwidth - self.histogram = _bins + self.histogram = _bins - # Return values + #Return values self.stddev = _stddev self.mean = _mean self.npix = _npix @@ -337,19 +333,19 @@ def printStats(self): """ Print the requested statistics values for those fields specified on input. """ print("--- Imagestats Results ---") - if (self.fields.find('npix') != -1): - print("Number of pixels : ", self.npix) - if (self.fields.find('min') != -1): - print("Minimum value : ", self.min) - if (self.fields.find('max') != -1): - print("Maximum value : ", self.max) - if (self.fields.find('stddev') != -1): - print("Standard Deviation: ", self.stddev) - if (self.fields.find('mean') != -1): - print("Mean : ", self.mean) - if (self.fields.find('mode') != -1): - print("Mode : ", self.mode) - if (self.fields.find('median') != -1): - print("Median : ", self.median) - if (self.fields.find('midpt') != -1): - print("Midpt : ", self.midpt) + if (self.fields.find('npix') != -1 ): + print("Number of pixels : ",self.npix) + if (self.fields.find('min') != -1 ): + print("Minimum value : ",self.min) + if (self.fields.find('max') != -1 ): + print("Maximum value : ",self.max) + if (self.fields.find('stddev') != -1 ): + print("Standard Deviation: ",self.stddev) + if (self.fields.find('mean') != -1 ): + print("Mean : ",self.mean) + if (self.fields.find('mode') != -1 ): + print("Mode : ",self.mode) + if (self.fields.find('median') != -1 ): + print("Median : ",self.median) + if (self.fields.find('midpt') != -1 ): + print("Midpt : ",self.midpt) diff --git a/stsci/imagestats/histogram1d.py b/stsci/imagestats/histogram1d.py index a9682a9..675f23b 100644 --- a/stsci/imagestats/histogram1d.py +++ b/stsci/imagestats/histogram1d.py @@ -7,9 +7,7 @@ :License: :doc:`../LICENSE` """ - import numpy as np - from . import buildHistogram @@ -33,7 +31,6 @@ class histogram1d: Zero value for the histogram range """ - def __init__(self, arrayInput, nbins, binWidth, zeroValue): # Initialize Object Attributes self._data = arrayInput.astype(np.float32) @@ -57,9 +54,9 @@ def __init__(self, arrayInput, nbins, binWidth, zeroValue): def _populateHistogram(self): """Call the C-code that actually populates the histogram""" - try: + try : buildHistogram.populate1DHist(self._data, self.histogram, - self.minValue, self.maxValue, self.binWidth) + self.minValue, self.maxValue, self.binWidth) except: if ((self._data.max() - self._data.min()) < self.binWidth): raise ValueError("In histogram1d class, the binWidth is " From 80fbaf0512a9ccd72044a75ff03ac169194ff38e Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Mon, 23 Jan 2023 08:35:49 -0500 Subject: [PATCH 6/8] read toml --- docs/source/conf.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8e2f773..c975601 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,10 +15,14 @@ import os import sys from datetime import datetime -import importlib +from pathlib import Path + import sphinx import stsci_rtd_theme from distutils.version import LooseVersion + +import tomli + try: from ConfigParser import ConfigParser except ImportError: @@ -112,10 +116,11 @@ def check_sphinx_version(expected_version): # General information about the project -project = setup_cfg['name'] -primary_author = setup_cfg["authors"][0] -author = f'{primary_author["name"]} <{primary_author["email"]}>' -copyright = f'{datetime.now().year}, {primary_author["name"]}' +with open(Path(__file__).parent.parent.parent / "pyproject.toml", "rb") as metadata_file: + metadata = tomli.load(metadata_file)['project'] +project = metadata['name'] +author = f'{metadata["authors"][0]["name"]} <{metadata["authors"][0]["email"]}>' +copyright = f'{datetime.today().year}, {author}' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the From a0eb3a4724a0726f3ff1dc3bd78f2468d140ea84 Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Wed, 19 Apr 2023 11:37:31 -0400 Subject: [PATCH 7/8] use `tomllib` in Python `>= 3.11` --- docs/source/conf.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c975601..1267c74 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -21,7 +21,10 @@ import stsci_rtd_theme from distutils.version import LooseVersion -import tomli +if sys.version_info < (3, 11): + import tomli as tomllib + else: + import tomllib try: from ConfigParser import ConfigParser @@ -40,7 +43,7 @@ # -- General configuration ------------------------------------------------ with open(Path(__file__).parent.parent.parent / "pyproject.toml", "rb") as configuration_file: - conf = tomli.load(configuration_file) + conf = tomllib.load(configuration_file) setup_cfg = conf['project'] # If your documentation needs a minimal Sphinx version, state it here. From c281b92af083d21660a82700ae6f83507290ecac Mon Sep 17 00:00:00 2001 From: Zach Burnett Date: Mon, 13 Nov 2023 11:14:21 -0500 Subject: [PATCH 8/8] pin Python to 3.7 and above --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f93dc23..211e419 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "stsci.imagestats" description = "Compute sigma-clipped statistics on data arrays" -requires-python = ">=3.6" +requires-python = ">=3.7" authors = [ { name = "Warren Hack", email = "help@stsci.edu" }, { name = "Christopher Hanley" },