diff --git a/.gitignore b/.gitignore index d21120ee95..65f9de7e0a 100644 --- a/.gitignore +++ b/.gitignore @@ -42,7 +42,6 @@ Thumbs.db # IDEs and editors /.idea/ -/.vscode/ # asv benchmark files /benchmarks/.asv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e891103226..e87eb88663 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,14 +3,11 @@ repos: rev: v0.8.6 hooks: - id: ruff - types_or: [python, pyi, jupyter] args: ["--fix"] - id: ruff-format - types_or: [python, pyi, jupyter] # The following can be removed once PLR0917 is out of preview - name: ruff preview rules id: ruff - types_or: [python, pyi, jupyter] args: ["--preview", "--select=PLR0917"] - repo: https://github.com/flying-sheep/bibfmt rev: v4.3.0 @@ -19,6 +16,15 @@ repos: args: - --sort-by-bibkey - --drop=abstract +- repo: https://github.com/biomejs/pre-commit + rev: v0.6.1 + hooks: + - id: biome-format + additional_dependencies: ["@biomejs/biome@1.9.4"] +- repo: https://github.com/ComPWA/taplo-pre-commit + rev: v0.9.3 + hooks: + - id: taplo-format - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: @@ -34,6 +40,3 @@ repos: - id: detect-private-key - id: no-commit-to-branch args: ["--branch=main"] - -ci: - autofix_prs: false diff --git a/.taplo.toml b/.taplo.toml new file mode 100644 index 0000000000..41a6cdc5cc --- /dev/null +++ b/.taplo.toml @@ -0,0 +1,5 @@ +[formatting] +array_auto_collapse = false +column_width = 120 +compact_arrays = false +indent_string = ' ' diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..d87ef7c54f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Build Documentation", + "type": "debugpy", + "request": "launch", + "module": "sphinx", + "args": ["-M", "html", ".", "_build"], + "cwd": "${workspaceFolder}/docs", + "console": "internalConsole", + "justMyCode": false, + }, + { + "name": "Python: Debug Test", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "purpose": ["debug-test"], + "console": "internalConsole", + "justMyCode": false, + "env": { "PYTEST_ADDOPTS": "--color=yes" }, + "presentation": { "hidden": true }, + }, + ], +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..ae719a4ec8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "[python][toml][json][jsonc]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit", + "source.fixAll": "explicit", + }, + }, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + }, + "[toml]": { + "editor.defaultFormatter": "tamasfe.even-better-toml", + }, + "[json][jsonc]": { + "editor.defaultFormatter": "biomejs.biome", + }, + "python.analysis.typeCheckingMode": "basic", + "python.testing.pytestArgs": ["-vv", "--color=yes"], + "python.testing.pytestEnabled": true, + "python.terminal.activateEnvironment": true, +} diff --git a/biome.jsonc b/biome.jsonc new file mode 100644 index 0000000000..cf4a677503 --- /dev/null +++ b/biome.jsonc @@ -0,0 +1,21 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "formatter": { + "indentStyle": "space", + "indentWidth": 4, + }, + "overrides": [ + { + "include": ["./.vscode/*.json", "**/*.jsonc", "**/asv.conf.json"], + "json": { + "formatter": { + "trailingCommas": "all", + }, + "parser": { + "allowComments": true, + "allowTrailingCommas": true, + }, + }, + }, + ], +} diff --git a/hatch.toml b/hatch.toml index 3163d5d82d..b0a1084c61 100644 --- a/hatch.toml +++ b/hatch.toml @@ -1,9 +1,9 @@ [envs.default] installer = "uv" -features = ["dev"] +features = [ "dev" ] [envs.docs] -features = ["doc"] +features = [ "doc" ] scripts.build = "sphinx-build -M html docs docs/_build -W --keep-going {args}" scripts.open = "python3 -m webbrowser -t docs/_build/html/index.html" scripts.clean = "git clean -fdX -- {args:docs}" @@ -14,23 +14,23 @@ scripts.build = "python3 ci/scripts/towncrier_automation.py {args}" scripts.clean = "git restore --source=HEAD --staged --worktree -- docs/release-notes" [envs.hatch-test] -default-args = [] -features = ["test", "dask-ml"] -extra-dependencies = ["ipykernel"] +default-args = [ ] +features = [ "test", "dask-ml" ] +extra-dependencies = [ "ipykernel" ] overrides.matrix.deps.env-vars = [ - { if = ["pre"], key = "UV_PRERELEASE", value = "allow" }, - { if = ["min"], key = "UV_CONSTRAINT", value = "ci/scanpy-min-deps.txt" }, + { if = [ "pre" ], key = "UV_PRERELEASE", value = "allow" }, + { if = [ "min" ], key = "UV_CONSTRAINT", value = "ci/scanpy-min-deps.txt" }, ] overrides.matrix.deps.pre-install-commands = [ - { if = ["min"], value = "uv run ci/scripts/min-deps.py pyproject.toml --all-extras -o ci/scanpy-min-deps.txt" }, + { if = [ "min" ], value = "uv run ci/scripts/min-deps.py pyproject.toml --all-extras -o ci/scanpy-min-deps.txt" }, ] overrides.matrix.deps.python = [ - { if = ["min"], value = "3.10" }, - { if = ["stable", "full", "pre"], value = "3.12" }, + { if = [ "min" ], value = "3.10" }, + { if = [ "stable", "full", "pre" ], value = "3.12" }, ] overrides.matrix.deps.features = [ - { if = ["full"], value = "test-full" }, + { if = [ "full" ], value = "test-full" }, ] [[envs.hatch-test.matrix]] -deps = ["stable", "full", "pre", "min"] +deps = [ "stable", "full", "pre", "min" ] diff --git a/pyproject.toml b/pyproject.toml index 00f02ad27c..94654363e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] build-backend = "hatchling.build" -requires = ["hatchling", "hatch-vcs"] +requires = [ "hatchling", "hatch-vcs" ] [project] name = "scanpy" @@ -8,23 +8,23 @@ description = "Single-Cell Analysis in Python." requires-python = ">=3.10" license = "BSD-3-clause" authors = [ - {name = "Alex Wolf"}, - {name = "Philipp Angerer"}, - {name = "Fidel Ramirez"}, - {name = "Isaac Virshup"}, - {name = "Sergei Rybakov"}, - {name = "Gokcen Eraslan"}, - {name = "Tom White"}, - {name = "Malte Luecken"}, - {name = "Davide Cittaro"}, - {name = "Tobias Callies"}, - {name = "Marius Lange"}, - {name = "Andrés R. Muñoz-Rojas"}, + { name = "Alex Wolf" }, + { name = "Philipp Angerer" }, + { name = "Fidel Ramirez" }, + { name = "Isaac Virshup" }, + { name = "Sergei Rybakov" }, + { name = "Gokcen Eraslan" }, + { name = "Tom White" }, + { name = "Malte Luecken" }, + { name = "Davide Cittaro" }, + { name = "Tobias Callies" }, + { name = "Marius Lange" }, + { name = "Andrés R. Muñoz-Rojas" }, ] maintainers = [ - {name = "Philipp Angerer", email = "phil.angerer@gmail.com"}, - {name = "Ilan Gold"}, - {name = "Severin Dicks"}, + { name = "Philipp Angerer", email = "phil.angerer@gmail.com" }, + { name = "Ilan Gold", email = "ilan.gold@helmholtz-munich.de" }, + { name = "Severin Dicks" }, ] readme = "README.md" classifiers = [ @@ -56,7 +56,7 @@ dependencies = [ "tqdm", "scikit-learn>=1.1,<1.6.0", "statsmodels>=0.13", - "patsy!=1.0.0", # https://github.com/pydata/patsy/issues/215 + "patsy!=1.0.0", # https://github.com/pydata/patsy/issues/215 "networkx>=2.7", "natsort", "joblib", @@ -65,10 +65,10 @@ dependencies = [ "pynndescent>=0.5", "packaging>=21.3", "session-info2", - "legacy-api-wrap>=1.4", # for positional API deprecations + "legacy-api-wrap>=1.4", # for positional API deprecations "typing-extensions; python_version < '3.13'", ] -dynamic = ["version"] +dynamic = [ "version" ] # https://docs.pypi.org/project_metadata/#project-urls [project.urls] @@ -120,13 +120,13 @@ doc = [ "sphinx-design", "sphinx-tabs", "readthedocs-sphinx-search", - "sphinxext-opengraph", # for nice cards when sharing on social + "sphinxext-opengraph", # for nice cards when sharing on social "sphinx-copybutton", "nbsphinx>=0.9", - "ipython>=7.20", # for nbsphinx code highlighting + "ipython>=7.20", # for nbsphinx code highlighting "matplotlib!=3.6.1", "sphinxcontrib-bibtex", - "setuptools", # undeclared dependency of sphinxcontrib-bibtex→pybtex + "setuptools", # undeclared dependency of sphinxcontrib-bibtex→pybtex # TODO: remove necessity for being able to import doc-linked classes "scanpy[paga,dask-ml]", "sam-algorithm", @@ -139,22 +139,22 @@ dev = [ "towncrier", ] # Algorithms -paga = ["igraph"] -louvain = ["igraph", "louvain>=0.6.0,!=0.6.2"] # Louvain community detection -leiden = ["igraph>=0.10", "leidenalg>=0.9.0"] # Leiden community detection -bbknn = ["bbknn"] # Batch balanced KNN (batch correction) -magic = ["magic-impute>=2.0"] # MAGIC imputation method -skmisc = ["scikit-misc>=0.1.3"] # highly_variable_genes method 'seurat_v3' -harmony = ["harmonypy"] # Harmony dataset integration -scanorama = ["scanorama"] # Scanorama dataset integration -scrublet = ["scikit-image"] # Doublet detection with automatic thresholds +paga = [ "igraph" ] +louvain = [ "igraph", "louvain>=0.6.0,!=0.6.2" ] # Louvain community detection +leiden = [ "igraph>=0.10", "leidenalg>=0.9.0" ] # Leiden community detection +bbknn = [ "bbknn" ] # Batch balanced KNN (batch correction) +magic = [ "magic-impute>=2.0" ] # MAGIC imputation method +skmisc = [ "scikit-misc>=0.1.3" ] # highly_variable_genes method 'seurat_v3' +harmony = [ "harmonypy" ] # Harmony dataset integration +scanorama = [ "scanorama" ] # Scanorama dataset integration +scrublet = [ "scikit-image" ] # Doublet detection with automatic thresholds # Acceleration -rapids = ["cudf>=0.9", "cuml>=0.9", "cugraph>=0.9"] # GPU accelerated calculation of neighbors -dask = ["dask[array]>=2022.09.2,<2024.8.0"] # Use the Dask parallelization engine -dask-ml = ["dask-ml", "scanpy[dask]"] # Dask-ML for sklearn-like API +rapids = [ "cudf>=0.9", "cuml>=0.9", "cugraph>=0.9" ] # GPU accelerated calculation of neighbors +dask = [ "dask[array]>=2022.09.2,<2024.8.0" ] # Use the Dask parallelization engine +dask-ml = [ "dask-ml", "scanpy[dask]" ] # Dask-ML for sklearn-like API [tool.hatch.build.targets.wheel] -packages = ["src/testing", "src/scanpy"] +packages = [ "src/testing", "src/scanpy" ] [tool.hatch.version] source = "vcs" raw-options.version_scheme = "release-branch-semver" @@ -169,8 +169,8 @@ addopts = [ "-ptesting.scanpy._pytest", "--pyargs", ] -testpaths = ["./tests", "./ci", "scanpy"] -norecursedirs = ["tests/_images"] +testpaths = [ "./tests", "./ci", "scanpy" ] +norecursedirs = [ "tests/_images" ] xfail_strict = true nunit_attach_on = "fail" markers = [ @@ -203,12 +203,12 @@ filterwarnings = [ [tool.coverage.run] data_file = "test-data/coverage" -source_pkgs = ["scanpy"] -omit = ["tests/*", "src/testing/*"] +source_pkgs = [ "scanpy" ] +omit = [ "tests/*", "src/testing/*" ] [tool.coverage.xml] output = "test-data/coverage.xml" [tool.coverage.paths] -source = [".", "**/site-packages"] +source = [ ".", "**/site-packages" ] [tool.coverage.report] exclude_also = [ "if __name__ == .__main__.:", @@ -218,7 +218,7 @@ exclude_also = [ ] [tool.ruff] -src = ["src"] +src = [ "src" ] [tool.ruff.format] docstring-code-format = true @@ -254,10 +254,10 @@ ignore = [ ] [tool.ruff.lint.per-file-ignores] # Do not assign a lambda expression, use a def -"src/scanpy/tools/_rank_genes_groups.py" = ["E731"] +"src/scanpy/tools/_rank_genes_groups.py" = [ "E731" ] [tool.ruff.lint.isort] -known-first-party = ["scanpy", "testing.scanpy"] -required-imports = ["from __future__ import annotations"] +known-first-party = [ "scanpy", "testing.scanpy" ] +required-imports = [ "from __future__ import annotations" ] [tool.ruff.lint.flake8-tidy-imports.banned-api] "pytest.importorskip".msg = "Use the “@needs” decorator/mark instead" "pandas.api.types.is_categorical_dtype".msg = "Use isinstance(s.dtype, CategoricalDtype) instead" @@ -267,7 +267,7 @@ required-imports = ["from __future__ import annotations"] "numba.jit".msg = "Use `scanpy._compat.njit` instead" "numba.njit".msg = "Use `scanpy._compat.njit` instead" [tool.ruff.lint.flake8-type-checking] -exempt-modules = [] +exempt-modules = [ ] strict = true [tool.towncrier] diff --git a/tests/_data/visium_data/1.0.0/spatial/scalefactors_json.json b/tests/_data/visium_data/1.0.0/spatial/scalefactors_json.json index 9f47f51518..5479b589c0 100644 --- a/tests/_data/visium_data/1.0.0/spatial/scalefactors_json.json +++ b/tests/_data/visium_data/1.0.0/spatial/scalefactors_json.json @@ -1 +1,6 @@ -{"spot_diameter_fullres": 89.42751063343188, "tissue_hires_scalef": 0.150015, "fiducial_diameter_fullres": 144.45982486939, "tissue_lowres_scalef": 0.045004502} \ No newline at end of file +{ + "spot_diameter_fullres": 89.42751063343188, + "tissue_hires_scalef": 0.150015, + "fiducial_diameter_fullres": 144.45982486939, + "tissue_lowres_scalef": 0.045004502 +}