From 9fe2e157181f7c35e1841e8cdaafefa35f921135 Mon Sep 17 00:00:00 2001 From: jaimergp Date: Tue, 25 Apr 2023 12:44:17 +0200 Subject: [PATCH] Add metadata and adjust as necessary to make it a functional package (#2) * add project metadata * adjust imports * add __init__ files * pre-commit --- .gitignore | 85 +++++++++ .pre-commit-config.yaml | 27 +++ LICENSE | 29 +++ README.md | 38 ++++ napari_plugin_manager/__init__.py | 0 napari_plugin_manager/_tests/__init__.py | 0 .../_tests/test_installer_process.py | 2 +- .../_tests/test_qt_plugin_dialog.py | 8 +- napari_plugin_manager/qt_package_installer.py | 13 +- napari_plugin_manager/qt_plugin_dialog.py | 30 +-- pyproject.toml | 176 ++++++++++++++++++ 11 files changed, 380 insertions(+), 28 deletions(-) create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 napari_plugin_manager/__init__.py create mode 100644 napari_plugin_manager/_tests/__init__.py create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..99f5161 --- /dev/null +++ b/.gitignore @@ -0,0 +1,85 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ +.napari_cache + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask instance folder +instance/ + +# Sphinx documentation +docs/_build/ + +# MkDocs documentation +/site/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# OS +.DS_Store + +# written by setuptools_scm +*/_version.py + +# pycharm stuff +.idea/ + +# ruff stuff +.ruff_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..83d62da --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +repos: + - repo: https://github.com/MarcoGorelli/absolufy-imports + rev: v0.3.1 + hooks: + - id: absolufy-imports + - repo: https://github.com/hadialqattan/pycln + rev: v2.1.3 + hooks: + - id: pycln + - repo: https://github.com/psf/black + rev: 22.12.0 + hooks: + - id: black + pass_filenames: true + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.237 + hooks: + - id: ruff + - repo: https://github.com/seddonym/import-linter + rev: v1.7.0 + hooks: + - id: import-linter + stages: [manual] + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.21.0 + hooks: + - id: check-github-workflows diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..11d7edc --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, Napari +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..50d6181 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# napari-plugin-manager + +> WIP, under active development + +[![License](https://img.shields.io/pypi/l/napari-plugin-manager.svg?color=green)](https://github.com/napari/napari-plugin-manager/raw/main/LICENSE) +[![PyPI](https://img.shields.io/pypi/v/napari-plugin-manager.svg?color=green)](https://pypi.org/project/napari-plugin-manager) +[![Python Version](https://img.shields.io/pypi/pyversions/napari-plugin-manager.svg?color=green)](https://python.org) +[![tests](https://github.com/napari/napari-plugin-manager/workflows/tests/badge.svg)](https://github.com/napari/napari-plugin-manager/actions) +[![codecov](https://codecov.io/gh/napari/napari-plugin-manager/branch/main/graph/badge.svg)](https://codecov.io/gh/napari/napari-plugin-manager) + +A plugin that adds a plugin manager to [napari]. + +---------------------------------- + +## Installation + +You can install `napari-plugin-manager` via [pip]: + + pip install napari-plugin-manager + +## License + +Distributed under the terms of the [BSD-3] license, +"napari-plugin-manager" is free and open source software + +## Issues + +If you encounter any problems, please [file an issue] along with a detailed description. + +[napari]: https://github.com/napari/napari +[Cookiecutter]: https://github.com/audreyr/cookiecutter +[@napari]: https://github.com/napari +[BSD-3]: http://opensource.org/licenses/BSD-3-Clause +[file an issue]: https://github.com/napari/napari-plugin-manager/issues +[napari]: https://github.com/napari/napari +[tox]: https://tox.readthedocs.io/en/latest/ +[pip]: https://pypi.org/project/pip/ +[PyPI]: https://pypi.org/ diff --git a/napari_plugin_manager/__init__.py b/napari_plugin_manager/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/napari_plugin_manager/_tests/__init__.py b/napari_plugin_manager/_tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/napari_plugin_manager/_tests/test_installer_process.py b/napari_plugin_manager/_tests/test_installer_process.py index 06bb332..7af288d 100644 --- a/napari_plugin_manager/_tests/test_installer_process.py +++ b/napari_plugin_manager/_tests/test_installer_process.py @@ -8,7 +8,7 @@ import pytest from qtpy.QtCore import QProcessEnvironment -from napari._qt.dialogs.qt_package_installer import ( +from napari_plugin_manager.qt_package_installer import ( AbstractInstallerTool, CondaInstallerTool, InstallerQueue, diff --git a/napari_plugin_manager/_tests/test_qt_plugin_dialog.py b/napari_plugin_manager/_tests/test_qt_plugin_dialog.py index 99fea02..d271562 100644 --- a/napari_plugin_manager/_tests/test_qt_plugin_dialog.py +++ b/napari_plugin_manager/_tests/test_qt_plugin_dialog.py @@ -2,15 +2,15 @@ from typing import Generator, Optional, Tuple from unittest.mock import patch +import napari.plugins import npe2 import pytest - -import napari.plugins -from napari._qt.dialogs import qt_plugin_dialog -from napari._qt.dialogs.qt_package_installer import InstallerActions from napari.plugins._tests.test_npe2 import mock_pm # noqa from napari.utils.translations import trans +from napari_plugin_manager import qt_plugin_dialog +from napari_plugin_manager.qt_package_installer import InstallerActions + def _iter_napari_pypi_plugin_info( conda_forge: bool = True, diff --git a/napari_plugin_manager/qt_package_installer.py b/napari_plugin_manager/qt_package_installer.py index a948336..4c07f6f 100644 --- a/napari_plugin_manager/qt_package_installer.py +++ b/napari_plugin_manager/qt_package_installer.py @@ -22,19 +22,16 @@ from tempfile import gettempdir, mkstemp from typing import Deque, Optional, Sequence, Tuple -from npe2 import PluginManager -from qtpy.QtCore import QObject, QProcess, QProcessEnvironment, Signal -from qtpy.QtWidgets import QTextEdit - -from napari._version import ( - version as _napari_version, - version_tuple as _napari_version_tuple, -) +from napari._version import version as _napari_version +from napari._version import version_tuple as _napari_version_tuple from napari.plugins import plugin_manager from napari.plugins.npe2api import _user_agent from napari.utils._appdirs import user_plugin_dir, user_site_packages from napari.utils.misc import StringEnum, running_as_bundled_app from napari.utils.translations import trans +from npe2 import PluginManager +from qtpy.QtCore import QObject, QProcess, QProcessEnvironment, Signal +from qtpy.QtWidgets import QTextEdit JobId = int log = getLogger(__name__) diff --git a/napari_plugin_manager/qt_plugin_dialog.py b/napari_plugin_manager/qt_plugin_dialog.py index ecace59..1278f74 100644 --- a/napari_plugin_manager/qt_plugin_dialog.py +++ b/napari_plugin_manager/qt_plugin_dialog.py @@ -7,7 +7,21 @@ from pathlib import Path from typing import Dict, List, Literal, Optional, Sequence, Tuple +import napari.plugins +import napari.resources import npe2 +from napari._qt.qt_resources import QColoredSVGIcon +from napari._qt.qthreading import create_worker +from napari._qt.widgets.qt_message_popup import WarnPopup +from napari._qt.widgets.qt_tooltip import QtToolTipLabel +from napari.plugins.npe2api import iter_napari_plugin_info +from napari.plugins.utils import normalized_name +from napari.settings import get_settings +from napari.utils.misc import ( + parse_version, + running_as_constructor_app, +) +from napari.utils.translations import trans from qtpy.QtCore import QEvent, QPoint, QSize, Qt, QTimer, Slot from qtpy.QtGui import QFont, QMovie from qtpy.QtWidgets import ( @@ -30,25 +44,11 @@ ) from superqt import QCollapsible, QElidingLabel -import napari.plugins -import napari.resources -from napari._qt.dialogs.qt_package_installer import ( +from napari_plugin_manager.qt_package_installer import ( InstallerActions, InstallerQueue, InstallerTools, ) -from napari._qt.qt_resources import QColoredSVGIcon -from napari._qt.qthreading import create_worker -from napari._qt.widgets.qt_message_popup import WarnPopup -from napari._qt.widgets.qt_tooltip import QtToolTipLabel -from napari.plugins.npe2api import iter_napari_plugin_info -from napari.plugins.utils import normalized_name -from napari.settings import get_settings -from napari.utils.misc import ( - parse_version, - running_as_constructor_app, -) -from napari.utils.translations import trans # TODO: add error icon and handle pip install errors diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c114f70 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,176 @@ +[build-system] +requires = [ + "setuptools >= 42", + "wheel", + "setuptools_scm[toml]>=3.4" +] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +write_to = "napari_plugin_manager/_version.py" + +[project] +name = "napari-plugin-manager" +description = "Install plugins for napari, in napari." +readme = "README.md" +authors = [ + {name = "napari team", email = "napari-steering-council@googlegroups.com"} +] +license = {file = "LICENSE"} +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: X11 Applications :: Qt", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Programming Language :: C", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Visualization", + "Topic :: Scientific/Engineering :: Information Analysis", + "Topic :: Scientific/Engineering :: Bio-Informatics", + "Topic :: Utilities", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS" +] +requires-python = ">=3.8" +dependencies = [ + "napari", + "npe2", + "qtpy", + "superqt", + "pip" +] +dynamic = [ + "version" +] + +[project.urls] +homepage = "https://github.com/napari/napari-plugin-manager" + +[tool.black] +target-version = ['py38', 'py39', 'py310'] +skip-string-normalization = true +line-length = 79 + +[tool.check-manifest] +ignore = [ + ".pre-commit-config.yaml", + "napari_plugin_manager/_version.py", # added during build by setuptools_scm + "*.pyi", # added by make typestubs +] + +[tool.ruff] +line-length = 79 +select = [ + "E", "F", "W", #flake8 + "UP", # pyupgrade + "I", # isort + "YTT", #flake8-2020 + "TCH", # flake8-type-checing + "BLE", # flake8-blind-exception + "B", # flake8-bugbear + "A", # flake8-builtins + "C4", # flake8-comprehensions + "ISC", # flake8-implicit-str-concat + "G", # flake8-logging-format + "PIE", # flake8-pie + "COM", # flake8-commas + "SIM", # flake8-simplify + "INP", # flake8-no-pep420 + "Q", # flake8-quotes + "RET", # flake8-return + "TID", # flake8-tidy-imports # replace absolutify import + "TRY", # tryceratops + "ICN", # flake8-import-conventions + "RUF", # ruff specyfic rules +] +ignore = [ + "E501", "UP006", "TCH001", "TCH002", "TCH003", + "A003", # flake8-builtins - we have class attributes violating these rule + "COM812", # flake8-commas - we don't like adding comma on single line of arguments + "SIM117", # flake8-simplify - we some of merged with statements are not looking great with black, reanble after drop python 3.9 + "Q000", + "RET504", # not fixed yet https://github.com/charliermarsh/ruff/issues/2950 + "TRY003", # require implement multiple exception class + "RUF005", # problem with numpy compatybility, see https://github.com/charliermarsh/ruff/issues/2142#issuecomment-1451038741 + +] + +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".mypy_cache", + ".pants.d", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", + "*vendored*", + "*_vendor*", +] + +target-version = "py38" +fix = true + +[tool.ruff.per-file-ignores] +"**/_tests/*.py" = ["B011", "INP001", "TRY301"] + +[tool.ruff.flake8-quotes] +docstring-quotes = "double" + +[tool.ruff.flake8-tidy-imports] +# Disallow all relative imports. +ban-relative-imports = "all" + +[tool.ruff.pyupgrade] +# Preserve types, even if a file imports `from __future__ import annotations`. +keep-runtime-typing = true + +[tool.ruff.isort] +known-first-party=['napari_plugin_manager'] + +[tool.pytest.ini_options] +# These follow standard library warnings filters syntax. See more here: +# https://docs.python.org/3/library/warnings.html#describing-warning-filters +addopts = "--maxfail=5 --durations=10 -rXxs" + +# NOTE: only put things that will never change in here. +# napari deprecation and future warnings should NOT go in here. +# instead... assert the warning with `pytest.warns()` in the relevant test, +# That way we can clean them up when no longer necessary +filterwarnings = [ + "error:::napari_plugin_manager", # turn warnings from napari into errors + "error:::test_.*", # turn warnings in our own tests into errors +] + +[tool.mypy] +files = "napari_plugin_manager" +ignore_missing_imports = true +exclude = [ + "_tests", +] +show_error_codes = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +check_untyped_defs = true +# # maybe someday :) +# disallow_any_generics = true +# no_implicit_reexport = true +# disallow_untyped_defs = true