[build-system]
requires = ["hatchling>=1.5", "hatch-nodejs-version"]
build-backend = "hatchling.build"

[project]
name = "nbformat"
dynamic = ["version"]
description = "The Jupyter Notebook format"
license = { file = "LICENSE" }
keywords = ["Interactive", "Interpreter", "Shell", "Web"]
classifiers = [
    "Intended Audience :: Developers",
    "Intended Audience :: System Administrators",
    "Intended Audience :: Science/Research",
    "License :: OSI Approved :: BSD License",
    "Programming Language :: Python",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Programming Language :: Python :: 3.14"
]
requires-python = ">=3.10"
dependencies = [
    "fastjsonschema>=2.15",
    "jsonschema>=2.6",
    "jupyter_core>=4.12,!=5.0.*",
    "traitlets>=5.1"
]

[[project.authors]]
name = "Jupyter Development Team"
email = "jupyter@googlegroups.com"

[project.readme]
text = "This package contains the base implementation of the Jupyter Notebook format,\nand Python APIs for working with notebooks."
content-type = "text/plain"

[project.urls]
Homepage = "https://jupyter.org"
Changelog = "https://github.com/jupyter/nbformat/blob/main/CHANGELOG.md"
Documentation = "https://nbformat.readthedocs.io/"
Repository = "https://github.com/jupyter/nbformat.git"


[project.optional-dependencies]
docs = [
"myst_parser",
"pydata_sphinx_theme",
"sphinx",
"sphinxcontrib_github_alt",
"sphinxcontrib-spelling",
"intersphinx_registry",
]
test = [
    "testpath",
    "pytest",
    "pre-commit",
    "packaging"
]

# These mirror the "docs" and "test" extras above, which are kept for
# backwards compatibility (`pip install nbformat[test]`) and are what the
# hatch environments below consume via `features`.
[dependency-groups]
docs = [
    "myst_parser",
    "pydata_sphinx_theme",
    "sphinx",
    "sphinxcontrib_github_alt",
    "sphinxcontrib-spelling",
    "intersphinx_registry",
]
test = [
    "testpath",
    "pytest",
    "pre-commit",
    "packaging",
]
dev = [{ include-group = "test" }]

[project.scripts]
jupyter-trust = "nbformat.sign:TrustNotebookApp.launch_instance"

[tool.hatch.version]
source = "nodejs"

[tool.hatch.envs.default]
installer = "uv"

[tool.hatch.envs.docs]
features = ["docs"]
[tool.hatch.envs.docs.scripts]
build = "make -C docs html SPHINXOPTS='-W'"

[tool.hatch.envs.test]
features = ["test"]
[tool.hatch.envs.test.scripts]
test = "PYTHONWARNDEFAULTENCODING=1 python -m pytest -vv {args}"
nowarn = "test -W default {args}"

[tool.hatch.envs.cov]
features = ["test"]
dependencies = ["coverage", "pytest-cov"]
[tool.hatch.envs.cov.scripts]
test = "python -m pytest -vv --cov nbformat --cov-branch --cov-report term-missing:skip-covered {args}"
nowarn = "test -W default {args}"

[tool.hatch.envs.lint]
detached = true
installer = "uv"
dependencies = ["pre-commit"]
[tool.hatch.envs.lint.scripts]
build = [
  "pre-commit run --all-files ruff-check",
  "pre-commit run --all-files ruff-format"
]

[tool.hatch.envs.typing]
dependencies = [ "pre-commit"]
detached = true
installer = "uv"
[tool.hatch.envs.typing.scripts]
test = "pre-commit run --all-files --hook-stage manual mypy"

[tool.pytest.ini_options]
minversion = "6.0"
xfail_strict = true
log_level = "info"
log_cli_level = "info"
addopts = [
  "-ra", "--durations=10", "--color=yes", "--doctest-modules",
   "--showlocals", "--strict-markers", "--strict-config"
]
testpaths = [
    "tests/",
]
filterwarnings = [
    "error",
    "ignore:Using or importing the ABCs from 'collections':DeprecationWarning:jsonschema",
    "module:Jupyter is migrating its paths to use standard platformdirs:DeprecationWarning",
]

[tool.coverage.report]
exclude_lines = [
  "pragma: no cover",
  "def __repr__",
  "if self.debug:",
  "if settings.DEBUG",
  "raise AssertionError",
  "raise NotImplementedError",
  "if 0:",
  "if __name__ == .__main__.:",
  "class .*\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]

[tool.mypy]
files = "nbformat"
python_version = "3.10"
strict = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
disable_error_code = ["no-untyped-def", "no-untyped-call"]
warn_unreachable = true

[tool.ruff]
line-length = 100

[tool.ruff.format]
exclude = ["^/tests.*ipynb$"]

[tool.ruff.lint]
extend-select = [
  "B",           # flake8-bugbear
  "I",           # isort
  "C4",          # flake8-comprehensions
  "EM",          # flake8-errmsg
  "ICN",         # flake8-import-conventions
  "G",           # flake8-logging-format
  "PGH",         # pygrep-hooks
  "PIE",         # flake8-pie
  "PL",          # pylint
  "PTH",         # flake8-use-pathlib
  "PT",          # flake8-pytest-style
  "RET",         # flake8-return
  "RUF",         # Ruff-specific
  "SIM",         # flake8-simplify
  "T20",         # flake8-print
  "UP",          # pyupgrade
  "YTT",         # flake8-2020
  "EXE",         # flake8-executable
  "PYI",         # flake8-pyi
  "S",           # flake8-bandit
]
ignore = [
  "PLR",    # Design related pylint codes
  "E501",   # Line too long (158 > 100 characters)
  "SIM105", # Use `contextlib.suppress(...)`
  "UP007",  # Use `X | Y` for type annotations
  "RET503", # Missing explicit `return` at the end of function able...
  "S101",   # Use of `assert` detected"
  "E731",   # Do not assign a `lambda` expression"
  "UP031",  # Use format specifiers instead of percent format
]
unfixable = [
  # Don't touch print statements
  "T201",
  # Don't touch noqa lines
  "RUF100",
]
isort.required-imports = ["from __future__ import annotations"]

[tool.ruff.lint.per-file-ignores]
# B011 Do not call assert False since python -O removes these calls
# F841 local variable 'foo' is assigned to but never used
# C408 Unnecessary `dict` call
# E402 Module level import not at top of file
# T201 `print` found
# B007 Loop control variable `i` not used within the loop body.
# N802 Function name `assertIn` should be lowercase
# RUF001 contains ambiguous unicode character '–' (did you mean '-'?)
# S101 Use of `assert` detected
# PLC1901 `cell.source == ""` can be simplified
"tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802", "RUF001", "RUF002", "S101", "PTH", "PT009", "PT011", "PT004", "PT027",
             "PLC1901", "PGH004"]
# F401 `nbxml.to_notebook` imported but unused
"nbformat/*__init__.py" = ["F401"]

[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false
mark-parentheses = false
parametrize-names-type = "csv"

[tool.coverage.run]
relative_files = true
source = ["nbformat"]

[tool.interrogate]
ignore-init-module=true
ignore-private=true
ignore-semiprivate=true
ignore-property-decorators=true
ignore-nested-functions=true
ignore-nested-classes=true
fail-under=100

[tool.check-wheel-contents]
ignore = ["W002"]

[tool.repo-review]
ignore = ["GH102"]

[tool.codespell]
skip = "*.ipynb"

[tool.jupyter-releaser]
# The `nbformat-schema` npm package is no longer published from CI (no npm
# credentials are configured for this repo). Skipping `build-npm` means no
# `*.tgz` ends up in the dist folder, so `publish-assets` never invokes
# `npm publish`; `check-npm` is skipped since it only checks that tarball.
# Pass `--force` (or remove these entries) if npm publishing is restored.
skip = ["build-npm", "check-npm"]
