diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 9ff8d58..0000000 --- a/.coveragerc +++ /dev/null @@ -1,2 +0,0 @@ -[run] -omit = ./doc/* diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 32e0996..8644027 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Python package +name: CI on: push: @@ -10,34 +10,123 @@ on: branches: [ master, dev, v0.7] jobs: - build: + check: + name: ${{ matrix.env.name }} + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + env: + - {"name": "pkg", "target": "show"} + - {"name": "lint", "target": "run"} + # - {"name": "type", "target": "run"} + - {"name": "docs", "target": "all"} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Let us have colors + run: echo "FORCE_COLOR=true" >> "$GITHUB_ENV" + - name: Install Hatch + uses: pypa/hatch@install + - name: Setup ${{ matrix.env.name }} + run: | + hatch -v env create ${{ matrix.env.name }} + hatch run ${{ matrix.env.name }}:pip freeze + - name: Run ${{ matrix.env.name }} + run: hatch -v run ${{ matrix.env.name }}:${{ matrix.env.target }} + test: + name: test py${{ matrix.python-version }} - seaborn-${{ matrix.seaborn-version }} runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: - python-version: [3.8, 3.9, '3.10', 3.11, 3.12] + # keep synchronized with hatch tests matrix + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + seaborn-version: ["0.11", "0.12", "0.13"] steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install flake8 coverage packaging - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with unittest - run: | - coverage run -m unittest discover tests - coverage report -m - - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v4 + - name: Setup python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Pick environment to run + run: | + import codecs + import os + env = "tests.py{}-{}".format("${{ matrix.python-version }}", "${{ matrix.seaborn-version }}") + print(f"Environment {env}") + with codecs.open(os.environ["GITHUB_ENV"], mode="a", encoding="utf-8") as file_handler: + file_handler.write("FORCE_COLOR=1\n") + file_handler.write(f"ENV={env}\n") + shell: python + - name: Install Hatch + uses: pypa/hatch@install + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Setup test environment + run: | + hatch -v env create ${ENV} + hatch run ${ENV}:pip freeze + shell: bash + - name: Run test suite + run: hatch -v run ${ENV}:run-cov + env: + CI_RUN: "yes" + shell: bash + - name: Upload coverage data + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.python-version }}-${{ matrix.seaborn-version }} + path: "report/.coverage.*" + + coverage: + name: coverage + runs-on: ubuntu-22.04 + needs: test + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Let us have colors + run: echo "FORCE_COLOR=true" >> "$GITHUB_ENV" + - name: Install Hatch + uses: pypa/hatch@install + - name: Setup coverage tool + run: | + hatch -v env create coverage + hatch run coverage:pip freeze + - name: Download coverage data + uses: actions/download-artifact@v4 + with: + pattern: coverage-* + path: report + merge-multiple: true + - name: Combine and report coverage + run: hatch run coverage:run + + - name: Upload HTML report + uses: actions/upload-artifact@v4 + with: + name: html-report + path: report/html + + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v4 + with: + directory: report + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 32de0af..524db39 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,8 @@ statannot.egg-info/requires.txt statannot.egg-info/SOURCES.txt statannot.egg-info/top_level.txt +usage/figures/* +report/ + # IDE files .idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d99bbae --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,19 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: check-yaml + # - id: end-of-file-fixer + # - id: trailing-whitespace + - repo: https://github.com/abravalheri/validate-pyproject + rev: v0.18 + hooks: + - id: validate-pyproject +# - repo: https://github.com/astral-sh/ruff-pre-commit +# rev: v0.5.5 +# hooks: +# # Run the linter. +# - id: ruff +# args: [ --fix, --unsafe-fixes ] +# # Run the formatter. +# - id: ruff-format diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index a7da3fc..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include requirements.txt -include LICENSE diff --git a/coverage.sh b/coverage.sh deleted file mode 100755 index c1419ac..0000000 --- a/coverage.sh +++ /dev/null @@ -1 +0,0 @@ -coverage run -m unittest discover tests && coverage report && coverage-badge -f -o coverage.svg \ No newline at end of file diff --git a/docs/source/_static/.gitignore b/docs/source/_static/.gitignore new file mode 100644 index 0000000..f935021 --- /dev/null +++ b/docs/source/_static/.gitignore @@ -0,0 +1 @@ +!.gitignore diff --git a/docs/source/conf.py b/docs/source/conf.py index d423ab2..9e4921f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,7 +33,12 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx_rtd_theme'] +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.coverage', + 'sphinx.ext.doctest', + 'sphinx_rtd_theme', +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/setup.rst b/docs/source/setup.rst deleted file mode 100644 index 552eb49..0000000 --- a/docs/source/setup.rst +++ /dev/null @@ -1,7 +0,0 @@ -setup module -============ - -.. automodule:: setup - :members: - :undoc-members: - :show-inheritance: diff --git a/hatch.toml b/hatch.toml new file mode 100644 index 0000000..4509a14 --- /dev/null +++ b/hatch.toml @@ -0,0 +1,147 @@ +# https://hatch.pypa.io/latest/config/environment/overview/ +# --------------------------------------------------------- +[envs.default] +description = "Development environment" +installer = "uv pip install" + +# --------------------------------------------------------- +[envs.pkg] +description = "package information" +[envs.pkg.scripts] +show = [ + "uv pip list --format=columns", + 'python -c "import sys; print(sys.version); print(sys.executable)"', +] + + +# --------------------------------------------------------- +[envs.lint] +template = "lint" +installer = "uv pip install" +description = "lint and format" +detached = true +dependencies = ["pre-commit"] + +[envs.lint.scripts] +run = "pre-commit run --all-files" + + +# --------------------------------------------------------- +[envs.docs] +template = "docs" +installer = "uv pip install" +description = "build and check documentation" +features = ["docs"] + +[envs.docs.scripts] +build = "sphinx-build -W --keep-going -b html docs/source docs/build" +doctest = "sphinx-build -W --keep-going -b doctest docs/source docs/build" +linkcheck = "sphinx-build -W --keep-going -b linkcheck docs/source docs/build" +all = ["build", "doctest", "linkcheck"] + + +# --------------------------------------------------------- +[envs.types] +template = "types" +installer = "uv pip install" +description = "Run the type checker" +dev-mode = false +dependencies = ["mypy"] + +[envs.types.scripts] +run = [ + """ + mypy --install-types --non-interactive --ignore-missing-imports \ + --config-file={root}/pyproject.toml {args:statannotations tests} + """, +] + + +# --------------------------------------------------------- +[envs.tests] +template = "tests" +installer = "uv pip install" +description = "Run the tests suite" +features = ["tests"] +extra-dependencies = [ + "matplotlib<3.9", + "seaborn=={matrix:seaborn_version}", +] + +[[envs.tests.matrix]] +# python = ["3.8", "3.9", "3.10", "3.11", "3.12"] +# seaborn_version = ["0.11", "0.12", "0.13"] +python = ["3.8", "3.9", "3.10", "3.11"] +seaborn_version = ["0.11"] + +[envs.tests.overrides] +matrix.seaborn_version.extra-dependencies = [ + "matplotlib<3.9", + "seaborn=={matrix:seaborn_version}", + { value = "pandas<2", if = ["0.11", "0.12"]}, + { value = "numpy<2", if = ["0.11", "0.12"]}, +] + +[envs.tests.env-vars] +COVERAGE_FILE = "report/.coverage.{matrix:python}-{matrix:seaborn_version}" +COVERAGE_PROCESS_START = "pyproject.toml" +_COVERAGE_SRC = "statannotations" + +[envs.tests.scripts] +run-cov = [ + """ + pytest --cov=statannotations \ + --cov-config=pyproject.toml --cov-context=test \ + --cov-report=term-missing:skip-covered \ + --cov-report html:report/html{matrix:python} \ + --cov-report xml:report/coverage{matrix:python}.xml \ + {args:-n auto --slow} + """, +] +run = "pytest {args:-n auto}" + + +# --------------------------------------------------------- +[envs.coverage] +template = "coverage" +installer = "uv pip install" +description = "combine coverage files" +detached = true +dependencies = [ + "coverage[toml]>=7.3", +] +env-vars = { COVERAGE_FILE = "report/.coverage" } + +[envs.coverage.scripts] +run = [ + "- coverage combine --rcfile=pyproject.toml report", + "coverage report {args:--skip-covered --show-missing}", + "coverage xml -o report/coverage.xml", + "coverage html -d report/html", +] + + +# --------------------------------------------------------- +[envs.examples] +template = "examples" +installer = "uv pip install" +description = "Run the examples" +python = "3.11" +extra-dependencies = [ + "matplotlib<3.9", + "seaborn=={matrix:seaborn_version}", +] + +[[envs.examples.matrix]] +seaborn_version = ["0.11", "0.12", "0.13"] + +[envs.examples.overrides] +matrix.seaborn_version.extra-dependencies = [ + "matplotlib<3.9", + "seaborn=={matrix:seaborn_version}", + { value = "pandas<2", if = ["0.11", "0.12"]}, + { value = "numpy<2", if = ["0.11", "0.12"]}, +] + +[envs.examples.scripts] +run = "- python usage/test_script.py {args}" diff --git a/make_doc.sh b/make_doc.sh deleted file mode 100755 index 2994014..0000000 --- a/make_doc.sh +++ /dev/null @@ -1,3 +0,0 @@ -cd docs && -# sphinx-apidoc -f -o source ../statannotations && -make html diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..448180c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,103 @@ +# https://peps.python.org/pep-0517/ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +# https://peps.python.org/pep-0621/ +[project] +name = "statannotations" +description = "add statistical significance or custom annotations on seaborn plots. Based on statannot 0.2.3" +readme = "README.md" +license = {text = "MIT License"} +requires-python = ">=3.7" +maintainers = [ + { name = "Florian Charlier", email = "trevis@cascliniques.be" }, +] +classifiers = [ + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "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", + "Programming Language :: Python :: 3.12", +] +dynamic = ["version"] +dependencies = [ + "matplotlib>=2.2.2", + "numpy>=1.12.1", + "pandas>=0.23.0", + "scipy>=1.1.0", + "seaborn>=0.9.0", +] + +[project.optional-dependencies] +extra = ["statsmodels"] +tests = [ + "statannotations[extra]", + "pytest>=6", + "pytest-cov>=4.1", + "pytest-skip-slow", + "pytest-xdist", + "packaging", + # "coverage[toml]>=7.3", +] +docs = [ + "sphinx", + "sphinx-rtd-theme", +] +dev = [ + "ipython", +] + +[project.urls] +Homepage = "https://github.com/trevismd/statannotations" + +# https://hatch.pypa.io/latest/config/metadata/ +[tool.hatch.version] +path = "statannotations/_version.py" + +[tool.hatch.build.targets.sdist] +only-include = [ + "/statannotations", + # "usage", + # "tests", + # "docs", +] + + +# https://docs.pytest.org/en/stable/reference/customize.html +[tool.pytest.ini_options] +minversion = "6.0" +testpaths = ["tests"] +addopts = "--import-mode=importlib" + + +# https://coverage.readthedocs.io/en/latest/config.html +[tool.coverage.report] +exclude_also = [ + "pragma: no.cover", + "if TYPE_CHECKING:", + "@overload", + "except ImportError", + "\\.\\.\\.", + "raise NotImplementedError()", + "if __name__ == .__main__.:", +] +show_missing = true +skip_covered = false + +[tool.coverage.run] +source = ["."] +branch = true +parallel = true +# Cannot use, it results in 'no-data-collected' +# relative_files = true + +[tool.coverage.paths] +source = [ + "statannotations", + "**/site-packages/statannotations", +] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 31019d5..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -numpy>=1.12.1 -seaborn>=0.9.0 -matplotlib>=2.2.2 -pandas>=0.23.0 -scipy>=1.1.0 -statsmodels -packaging diff --git a/setup.py b/setup.py deleted file mode 100644 index 58ac68e..0000000 --- a/setup.py +++ /dev/null @@ -1,41 +0,0 @@ -from setuptools import find_packages, setup -import re - -with open("README.md", "r") as f: - long_description = f.read() - -VERSIONFILE = "statannotations/_version.py" -verstrline = open(VERSIONFILE, "rt").read() -match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", verstrline, re.M) -if match: - version = match.group(1) -else: - raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,)) - - -def remove_dev_only(list_of_dependencies): - return [dep for dep in list_of_dependencies - if dep.strip() not in ("statsmodels", "packaging")] - - -setup( - name="statannotations", - version=version, - maintainer="Florian Charlier", - maintainer_email="trevis@cascliniques.be", - description=("add statistical significance or custom annotations on " - "seaborn plots. Based on statannot 0.2.3"), - license="MIT License", - license_file="LICENSE", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/trevismd/statannotations", - packages=find_packages(exclude=("tests", "usage", "docs", "build", "dist")), - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - ], - install_requires=remove_dev_only(open("requirements.txt").readlines()), - python_requires='>=3.6', -) diff --git a/usage/.png b/usage/.png deleted file mode 100644 index 9bfb18e..0000000 Binary files a/usage/.png and /dev/null differ