From 7b68e791de4afc88df1b058352dbac99b34560e4 Mon Sep 17 00:00:00 2001 From: Matt Fisher Date: Sat, 20 May 2023 18:53:08 -0600 Subject: [PATCH 1/4] Drop support for Python 2 --- README.rst | 2 +- setup.cfg | 3 --- setup.py | 6 ++---- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 790594a..0339be0 100644 --- a/README.rst +++ b/README.rst @@ -23,7 +23,7 @@ Contact: Nathaniel J. Smith and Stéfan van der Walt Dependencies: - * Python 2.6+, or 3.3+ + * Python 3.7+ * `colorspacious `_ * Matplotlib * NumPy diff --git a/setup.cfg b/setup.cfg index 5c6311d..0c9e0fc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,2 @@ -[bdist_wheel] -universal=1 - [metadata] license_file = LICENSE diff --git a/setup.py b/setup.py index 796b780..de84229 100644 --- a/setup.py +++ b/setup.py @@ -6,24 +6,22 @@ # Must be one line or PyPI will cut it off DESC = ("A colormap tool") - LONG_DESC = open("README.rst").read() setup( name="viscm", - version="0.9", + version="0.10", description=DESC, long_description=LONG_DESC, author="Nathaniel J. Smith, Stefan van der Walt", author_email="njs@pobox.com, stefanv@berkeley.edu", - url="https://github.com/bids/viscm", + url="https://github.com/matplotlib/viscm", license="MIT", classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", ], packages=find_packages(), From 1df583877c4033f7bbad1a3089b453c1a8c1fc36 Mon Sep 17 00:00:00 2001 From: Matt Fisher Date: Sat, 20 May 2023 20:45:47 -0600 Subject: [PATCH 2/4] Migrate to modern packaging toolchain --- doc/contributing.md | 23 ++++++++++++++++++++++ environment.yml | 12 ++++++++++++ pyproject.toml | 48 +++++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 2 -- setup.py | 31 ++--------------------------- viscm/__init__.py | 1 - viscm/__main__.py | 3 +-- viscm/gui.py | 5 +++-- 8 files changed, 89 insertions(+), 36 deletions(-) create mode 100644 doc/contributing.md create mode 100644 environment.yml create mode 100644 pyproject.toml delete mode 100644 setup.cfg diff --git a/doc/contributing.md b/doc/contributing.md new file mode 100644 index 0000000..fc5825b --- /dev/null +++ b/doc/contributing.md @@ -0,0 +1,23 @@ +# Contributing + +Install development dependencies: + +``` +conda env create # or `mamba env create` +``` + + +## Development install + +``` +pip install -e . +``` + + +## Testing the build + +``` +rm -rf dist +python -m build +pip install dist/*.whl # or `dist/*.tar.gz` +``` diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..33c0a90 --- /dev/null +++ b/environment.yml @@ -0,0 +1,12 @@ +name: "viscm" +channels: + - "conda-forge" + - "nodefaults" +dependencies: + - "python ~=3.11" + - "numpy ~=1.24" + - "matplotlib ~=3.7" + - "colorspacious ~=1.1" + - "scipy ~=1.10" + - pip: + - "build ~=0.10" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..308e631 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,48 @@ +[project] +name = "viscm" +dynamic = ["version"] +description = "A colormap tool" +readme = "README.rst" +authors = [ + {name = "Nathaniel J. Smith", email = "njs@pobox.com"}, + {name = "Stefan van der Walt", email = "stefanv@berkeley.edu"}, +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", +] + +requires-python = "~=3.7" +dependencies = [ + "numpy", + "matplotlib", + "colorspacious", + "scipy", +] + +[project.urls] +repository = "https://github.com/matplotlib/viscm" +# documentation = "https://viscm.readthedocs.io" + +[project.license] +text = "MIT" +files = ["LICENSE"] + +[project.scripts] +viscm = "viscm.gui:main" + + +[build-system] +requires = ["setuptools", "setuptools_scm"] +build-backend = "setuptools.build_meta" + +[tool.setuptools] +zip-safe = false +packages = {find = {}} +package-data = {viscm = ["examples/*"]} + + +# [tool.black] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 0c9e0fc..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[metadata] -license_file = LICENSE diff --git a/setup.py b/setup.py index de84229..d5d43d7 100644 --- a/setup.py +++ b/setup.py @@ -1,30 +1,3 @@ -from setuptools import setup, find_packages -import sys -import os.path +from setuptools import setup -import numpy as np - -# Must be one line or PyPI will cut it off -DESC = ("A colormap tool") -LONG_DESC = open("README.rst").read() - -setup( - name="viscm", - version="0.10", - description=DESC, - long_description=LONG_DESC, - author="Nathaniel J. Smith, Stefan van der Walt", - author_email="njs@pobox.com, stefanv@berkeley.edu", - url="https://github.com/matplotlib/viscm", - license="MIT", - classifiers = - [ "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - ], - packages=find_packages(), - install_requires=["numpy", "matplotlib", "colorspacious", "scipy"], - package_data={'viscm': ['examples/*']}, -) +setup(use_scm_version=True) diff --git a/viscm/__init__.py b/viscm/__init__.py index 2152218..f51aa85 100644 --- a/viscm/__init__.py +++ b/viscm/__init__.py @@ -1,4 +1,3 @@ -# This file is part of pycam02ucs # Copyright (C) 2014 Nathaniel Smith # See file LICENSE.txt for license information. diff --git a/viscm/__main__.py b/viscm/__main__.py index db0cdb5..144eb2e 100644 --- a/viscm/__main__.py +++ b/viscm/__main__.py @@ -3,6 +3,5 @@ # Copyright (C) 2015 Stefan van der Walt # See file LICENSE.txt for license information. -import sys from .gui import main -main(sys.argv[1:]) +main() diff --git a/viscm/gui.py b/viscm/gui.py index ecd3bc6..5fabe0a 100644 --- a/viscm/gui.py +++ b/viscm/gui.py @@ -948,8 +948,9 @@ def load(self, path): self.name = path -def main(argv): +def main(): import argparse + argv = sys.argv[1:] # Usage: # python -m viscm @@ -1331,4 +1332,4 @@ def loadviewer(self): if __name__ == "__main__": - main(sys.argv[1:]) + main() From ca5a02814af8a6bf427ce7c5407c6670b177a470 Mon Sep 17 00:00:00 2001 From: Matt Fisher Date: Sat, 20 May 2023 21:10:12 -0600 Subject: [PATCH 3/4] Extract CLI into new module --- pyproject.toml | 2 +- viscm/__main__.py | 4 +- viscm/cli.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++ viscm/gui.py | 106 +------------------------------------------ 4 files changed, 115 insertions(+), 108 deletions(-) create mode 100644 viscm/cli.py diff --git a/pyproject.toml b/pyproject.toml index 308e631..1b53c90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ text = "MIT" files = ["LICENSE"] [project.scripts] -viscm = "viscm.gui:main" +viscm = "viscm.cli:cli" [build-system] diff --git a/viscm/__main__.py b/viscm/__main__.py index 144eb2e..f4b3e03 100644 --- a/viscm/__main__.py +++ b/viscm/__main__.py @@ -3,5 +3,5 @@ # Copyright (C) 2015 Stefan van der Walt # See file LICENSE.txt for license information. -from .gui import main -main() +from .cli import cli +cli() diff --git a/viscm/cli.py b/viscm/cli.py new file mode 100644 index 0000000..9960804 --- /dev/null +++ b/viscm/cli.py @@ -0,0 +1,111 @@ +import sys + +import matplotlib.pyplot as plt + +from . import gui + + +def cli(): + import argparse + argv = sys.argv[1:] + + # Usage: + # python -m viscm + # python -m viscm edit + # python -m viscm edit + # (file.py must define some appropriate globals) + # python -m viscm view + # (file.py must define a global named "test_cm") + # python -m viscm view "matplotlib builtin colormap" + # python -m viscm view --save=foo.png ... + + parser = argparse.ArgumentParser( + prog="python -m viscm", + description="A colormap tool.", + ) + parser.add_argument("action", metavar="ACTION", + help="'edit' or 'view' (or 'show', same as 'view')", + choices=["edit", "view", "show"], + default="edit", + nargs="?") + parser.add_argument("colormap", metavar="COLORMAP", + default=None, + help="A .json file saved from the editor, or " + "the name of a matplotlib builtin colormap", + nargs="?") + parser.add_argument("--uniform-space", metavar="SPACE", + default="CAM02-UCS", + dest="uniform_space", + help="The perceptually uniform space to use. Usually " + "you should leave this alone. You can pass 'CIELab' " + "if you're curious how uniform some colormap is in " + "CIELab space. You can pass 'buggy-CAM02-UCS' if " + "you're trying to reproduce the matplotlib colormaps " + "(which turn out to have had a small bug in the " + "assumed sRGB viewing conditions) from their bezier " + "curves.") + parser.add_argument("-t", "--type", type=str, + default="linear", choices=["linear", "diverging", "diverging-continuous"], + help="Choose a colormap type. Supported options are 'linear', 'diverging', and 'diverging-continuous") + parser.add_argument("-m", "--method", type=str, + default="CatmulClark", choices=["Bezier", "CatmulClark"], + help="Choose a spline construction method. 'CatmulClark' is the default, but you may choose the legacy option 'Bezier'") + parser.add_argument("--save", metavar="FILE", + default=None, + help="Immediately save visualization to a file " + "(view-mode only).") + parser.add_argument("--quit", default=False, action="store_true", + help="Quit immediately after starting " + "(useful with --save).") + args = parser.parse_args(argv) + + cm = gui.Colormap(args.type, args.method, args.uniform_space) + app = gui.QtWidgets.QApplication([]) + + if args.colormap: + cm.load(args.colormap) + + + # Easter egg! I keep typing 'show' instead of 'view' so accept both + if args.action in ("view", "show"): + if cm is None: + sys.exit("Please specify a colormap") + fig = plt.figure() + figureCanvas = gui.FigureCanvas(fig) + v = gui.viscm(cm.cmap, name=cm.name, figure=fig, uniform_space=cm.uniform_space) + mainwindow = gui.ViewerWindow(figureCanvas, v, cm.name) + if args.save is not None: + v.figure.set_size_inches(20, 12) + v.figure.savefig(args.save) + elif args.action == "edit": + if not cm.can_edit: + sys.exit("Sorry, I don't know how to edit the specified colormap") + # Hold a reference so it doesn't get GC'ed + fig = plt.figure() + figureCanvas = gui.FigureCanvas(fig) + v = gui.viscm_editor(figure=fig, uniform_space=cm.uniform_space, cmtype=cm.cmtype, method=cm.method, **cm.params) + mainwindow = gui.EditorWindow(figureCanvas, v) + else: + raise RuntimeError("can't happen") + + if args.quit: + sys.exit() + + figureCanvas.setSizePolicy(gui.QtWidgets.QSizePolicy.Expanding, + gui.QtWidgets.QSizePolicy.Expanding) + figureCanvas.updateGeometry() + + mainwindow.resize(800, 600) + mainwindow.show() + + # PyQt messes up signal handling by default. Python signal handlers (e.g., + # the default handler for SIGINT that raises KeyboardInterrupt) can only + # run when we enter the Python interpreter, which doesn't happen while + # idling in the Qt mainloop. (Unless we register a timer to poll + # explicitly.) So here we unregister Python's default signal handler and + # replace it with... the *operating system's* default signal handler, so + # instead of a KeyboardInterrupt our process just exits. + import signal + signal.signal(signal.SIGINT, signal.SIG_DFL) + + app.exec_() diff --git a/viscm/gui.py b/viscm/gui.py index 5fabe0a..669a529 100644 --- a/viscm/gui.py +++ b/viscm/gui.py @@ -948,117 +948,13 @@ def load(self, path): self.name = path -def main(): - import argparse - argv = sys.argv[1:] - - # Usage: - # python -m viscm - # python -m viscm edit - # python -m viscm edit - # (file.py must define some appropriate globals) - # python -m viscm view - # (file.py must define a global named "test_cm") - # python -m viscm view "matplotlib builtin colormap" - # python -m viscm view --save=foo.png ... - - parser = argparse.ArgumentParser( - prog="python -m viscm", - description="A colormap tool.", - ) - parser.add_argument("action", metavar="ACTION", - help="'edit' or 'view' (or 'show', same as 'view')", - choices=["edit", "view", "show"], - default="edit", - nargs="?") - parser.add_argument("colormap", metavar="COLORMAP", - default=None, - help="A .json file saved from the editor, or " - "the name of a matplotlib builtin colormap", - nargs="?") - parser.add_argument("--uniform-space", metavar="SPACE", - default="CAM02-UCS", - dest="uniform_space", - help="The perceptually uniform space to use. Usually " - "you should leave this alone. You can pass 'CIELab' " - "if you're curious how uniform some colormap is in " - "CIELab space. You can pass 'buggy-CAM02-UCS' if " - "you're trying to reproduce the matplotlib colormaps " - "(which turn out to have had a small bug in the " - "assumed sRGB viewing conditions) from their bezier " - "curves.") - parser.add_argument("-t", "--type", type=str, - default="linear", choices=["linear", "diverging", "diverging-continuous"], - help="Choose a colormap type. Supported options are 'linear', 'diverging', and 'diverging-continuous") - parser.add_argument("-m", "--method", type=str, - default="CatmulClark", choices=["Bezier", "CatmulClark"], - help="Choose a spline construction method. 'CatmulClark' is the default, but you may choose the legacy option 'Bezier'") - parser.add_argument("--save", metavar="FILE", - default=None, - help="Immediately save visualization to a file " - "(view-mode only).") - parser.add_argument("--quit", default=False, action="store_true", - help="Quit immediately after starting " - "(useful with --save).") - args = parser.parse_args(argv) - - cm = Colormap(args.type, args.method, args.uniform_space) - app = QtWidgets.QApplication([]) - - if args.colormap: - cm.load(args.colormap) - - - # Easter egg! I keep typing 'show' instead of 'view' so accept both - if args.action in ("view", "show"): - if cm is None: - sys.exit("Please specify a colormap") - fig = plt.figure() - figureCanvas = FigureCanvas(fig) - v = viscm(cm.cmap, name=cm.name, figure=fig, uniform_space=cm.uniform_space) - mainwindow = ViewerWindow(figureCanvas, v, cm.name) - if args.save is not None: - v.figure.set_size_inches(20, 12) - v.figure.savefig(args.save) - elif args.action == "edit": - if not cm.can_edit: - sys.exit("Sorry, I don't know how to edit the specified colormap") - # Hold a reference so it doesn't get GC'ed - fig = plt.figure() - figureCanvas = FigureCanvas(fig) - v = viscm_editor(figure=fig, uniform_space=cm.uniform_space, cmtype=cm.cmtype, method=cm.method, **cm.params) - mainwindow = EditorWindow(figureCanvas, v) - else: - raise RuntimeError("can't happen") - - if args.quit: - sys.exit() - - figureCanvas.setSizePolicy(QtWidgets.QSizePolicy.Expanding, - QtWidgets.QSizePolicy.Expanding) - figureCanvas.updateGeometry() - - mainwindow.resize(800, 600) - mainwindow.show() - - # PyQt messes up signal handling by default. Python signal handlers (e.g., - # the default handler for SIGINT that raises KeyboardInterrupt) can only - # run when we enter the Python interpreter, which doesn't happen while - # idling in the Qt mainloop. (Unless we register a timer to poll - # explicitly.) So here we unregister Python's default signal handler and - # replace it with... the *operating system's* default signal handler, so - # instead of a KeyboardInterrupt our process just exits. - import signal - signal.signal(signal.SIGINT, signal.SIG_DFL) - - app.exec_() - def about(): QtWidgets.QMessageBox.about(None, "VISCM", "Copyright (C) 2015-2016 Nathaniel Smith\n" + "Copyright (C) 2015-2016 Stéfan van der Walt\n" "Copyright (C) 2016 Hankun Zhao") + class ViewerWindow(QtWidgets.QMainWindow): def __init__(self, figurecanvas, viscm, cmapname, parent=None): QtWidgets.QMainWindow.__init__(self, parent) From 019945d4ed7f069fd4242c12b43cd8f4c4cf9fe5 Mon Sep 17 00:00:00 2001 From: Matt Fisher Date: Sat, 20 May 2023 21:43:02 -0600 Subject: [PATCH 4/4] Code / docs cleanup * Add anaconda.org URL to README * Fix minor error in README * Document passing a .py file as COLORMAP, clean up unnecessary comment * Relocate `__name__ == "__main__"` check to `cli` module --- README.rst | 5 +++-- viscm/cli.py | 21 ++++++++------------- viscm/gui.py | 4 ---- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/README.rst b/README.rst index 0339be0..c6c76c7 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,8 @@ resulting visualizations and use the editor tool `on this website `_. Downloads: - https://pypi.python.org/pypi/viscm/ + * https://pypi.python.org/pypi/viscm/ + * https://anaconda.org/conda-forge/viscm/ Code and bug tracker: https://github.com/matplotlib/viscm @@ -29,4 +30,4 @@ Dependencies: * NumPy License: - MIT, see LICENSE.txt for details. + MIT, see `LICENSE `__ for details. diff --git a/viscm/cli.py b/viscm/cli.py index 9960804..246ae46 100644 --- a/viscm/cli.py +++ b/viscm/cli.py @@ -2,23 +2,13 @@ import matplotlib.pyplot as plt -from . import gui +from viscm import gui def cli(): import argparse argv = sys.argv[1:] - # Usage: - # python -m viscm - # python -m viscm edit - # python -m viscm edit - # (file.py must define some appropriate globals) - # python -m viscm view - # (file.py must define a global named "test_cm") - # python -m viscm view "matplotlib builtin colormap" - # python -m viscm view --save=foo.png ... - parser = argparse.ArgumentParser( prog="python -m viscm", description="A colormap tool.", @@ -30,8 +20,9 @@ def cli(): nargs="?") parser.add_argument("colormap", metavar="COLORMAP", default=None, - help="A .json file saved from the editor, or " - "the name of a matplotlib builtin colormap", + help="A .json file saved from the editor, a .py file containing" + " a global named `test_cm`, or the name of a matplotlib" + " builtin colormap", nargs="?") parser.add_argument("--uniform-space", metavar="SPACE", default="CAM02-UCS", @@ -109,3 +100,7 @@ def cli(): signal.signal(signal.SIGINT, signal.SIG_DFL) app.exec_() + + +if __name__ == "__main__": + cli() diff --git a/viscm/gui.py b/viscm/gui.py index 669a529..71e44ce 100644 --- a/viscm/gui.py +++ b/viscm/gui.py @@ -1225,7 +1225,3 @@ def loadviewer(self): newwindow.resize(800, 600) newwindow.show() - - -if __name__ == "__main__": - main()