diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index f10a5bc1..cbd920f6 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,8 +1,10 @@
version: 2
updates:
- # Set update schedule for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
- # Check for updates to GitHub Actions every weekday
+ interval: "weekly"
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
interval: "weekly"
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index a0d879b9..8a47563e 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -50,12 +50,18 @@ jobs:
codecov
- run: hatch version 100.100.100
- pre_commit:
- runs-on: ubuntu-20.04
+ test_lint:
+ name: Test Lint
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- - uses: jupyterlab/maintainer-tools/.github/actions/pre-commit@v1
+ - name: Run Linters
+ run: |
+ hatch run typing:test
+ hatch run lint:style
+ pipx run 'validate-pyproject[all]' pyproject.toml
+ pipx run doc8 --max-line-length=200
docs:
runs-on: ubuntu-latest
@@ -142,7 +148,7 @@ jobs:
if: always()
needs:
- tests
- - pre_commit
+ - test_lint
- docs
- test_minimum_versions
- test_prereleases
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 99467558..ff708b29 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,3 +1,6 @@
+ci:
+ autoupdate_schedule: monthly
+
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
@@ -15,59 +18,23 @@ repos:
- id: check-builtin-literals
- id: trailing-whitespace
- - repo: https://github.com/psf/black
- rev: 22.10.0
- hooks:
- - id: black
-
- - repo: https://github.com/PyCQA/isort
- rev: 5.10.1
- hooks:
- - id: isort
- files: \.py$
-
- - repo: https://github.com/pre-commit/mirrors-mypy
- rev: v0.991
- hooks:
- - id: mypy
- additional_dependencies: [types-requests, traitlets, jupyter_core]
- stages: [manual]
-
- - repo: https://github.com/abravalheri/validate-pyproject
- rev: v0.10.1
+ - repo: https://github.com/python-jsonschema/check-jsonschema
+ rev: 0.19.2
hooks:
- - id: validate-pyproject
- stages: [manual]
+ - id: check-github-workflows
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.16
hooks:
- id: mdformat
- - repo: https://github.com/asottile/pyupgrade
- rev: v3.3.0
- hooks:
- - id: pyupgrade
- args: [--py37-plus]
-
- - repo: https://github.com/PyCQA/doc8
- rev: v1.0.0
- hooks:
- - id: doc8
- args: [--max-line-length=200]
- exclude: docs/source/other/full-config.rst
- stages: [manual]
-
- - repo: https://github.com/john-hen/Flake8-pyproject
- rev: 1.2.2
+ - repo: https://github.com/psf/black
+ rev: 22.10.0
hooks:
- - id: Flake8-pyproject
- alias: flake8
- additional_dependencies:
- ["flake8-bugbear==22.6.22", "flake8-implicit-str-concat==0.2.0"]
- stages: [manual]
+ - id: black
- - repo: https://github.com/python-jsonschema/check-jsonschema
- rev: 0.19.2
+ - repo: https://github.com/charliermarsh/ruff-pre-commit
+ rev: v0.0.165
hooks:
- - id: check-github-workflows
+ - id: ruff
+ args: ["--fix"]
diff --git a/nbformat/_imports.py b/nbformat/_imports.py
index 1c6c97ac..59fe2f0e 100644
--- a/nbformat/_imports.py
+++ b/nbformat/_imports.py
@@ -33,7 +33,7 @@ def import_item(name):
try:
pak = getattr(module, obj)
except AttributeError:
- raise ImportError("No module named %s" % obj)
+ raise ImportError("No module named %s" % obj) from None
return pak
else:
# called with un-dotted string
diff --git a/nbformat/_struct.py b/nbformat/_struct.py
index f1ab4e47..cb70211e 100644
--- a/nbformat/_struct.py
+++ b/nbformat/_struct.py
@@ -102,7 +102,7 @@ def __setattr__(self, key, value):
try:
self.__setitem__(key, value)
except KeyError as e:
- raise AttributeError(e)
+ raise AttributeError(e) from None
def __getattr__(self, key):
"""Get an attr by calling :meth:`dict.__getitem__`.
@@ -127,7 +127,7 @@ def __getattr__(self, key):
try:
result = self[key]
except KeyError:
- raise AttributeError(key)
+ raise AttributeError(key) from None
else:
return result
diff --git a/nbformat/converter.py b/nbformat/converter.py
index d49a197e..e6969926 100644
--- a/nbformat/converter.py
+++ b/nbformat/converter.py
@@ -62,7 +62,7 @@ def convert(nb, to_version):
except AttributeError as e:
raise ValidationError(
f"Notebook could not be converted from version {version} to version {step_version} because it's missing a key: {e}"
- )
+ ) from None
# Recursively convert until target version is reached.
return convert(converted, to_version)
diff --git a/nbformat/json_compat.py b/nbformat/json_compat.py
index 737a9111..7cd87a03 100644
--- a/nbformat/json_compat.py
+++ b/nbformat/json_compat.py
@@ -47,7 +47,7 @@ def validate(self, data):
try:
self._validator(data)
except _JsonSchemaException as error:
- raise ValidationError(str(error), schema_path=error.path)
+ raise ValidationError(str(error), schema_path=error.path) from error
def iter_errors(self, data, schema=None):
if schema is not None:
diff --git a/nbformat/reader.py b/nbformat/reader.py
index 54d91110..47759b45 100644
--- a/nbformat/reader.py
+++ b/nbformat/reader.py
@@ -74,7 +74,9 @@ def reads(s, **kwargs):
try:
return versions[major].to_notebook_json(nb_dict, minor=minor)
except AttributeError as e:
- raise ValidationError(f"The notebook is invalid and is missing an expected key: {e}")
+ raise ValidationError(
+ f"The notebook is invalid and is missing an expected key: {e}"
+ ) from None
else:
raise NBFormatError("Unsupported nbformat version %s" % major)
diff --git a/nbformat/sign.py b/nbformat/sign.py
index 6009e9ba..6011ef37 100644
--- a/nbformat/sign.py
+++ b/nbformat/sign.py
@@ -23,18 +23,7 @@
from base64 import encodebytes
from jupyter_core.application import JupyterApp, base_flags
-from traitlets import (
- Any,
- Bool,
- Bytes,
- Callable,
- Enum,
- Instance,
- Integer,
- Unicode,
- default,
- observe,
-)
+from traitlets import Any, Bool, Bytes, Callable, Enum, Instance, Integer, Unicode, default, observe
from traitlets.config import LoggingConfigurable, MultipleInstanceError
from . import NO_CONVERT, __version__, read, reads
@@ -139,9 +128,9 @@ def close(self):
self.db.close()
def _connect_db(self, db_file):
- kwargs: t.Dict[str, t.Any] = dict(
- detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES
- )
+ kwargs: t.Dict[str, t.Any] = {
+ "detect_types": sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES
+ }
db = None
try:
db = sqlite3.connect(db_file, **kwargs)
diff --git a/nbformat/v1/nbbase.py b/nbformat/v1/nbbase.py
index 441f6fa9..5b1c0c41 100644
--- a/nbformat/v1/nbbase.py
+++ b/nbformat/v1/nbbase.py
@@ -18,6 +18,7 @@
from .._struct import Struct
+
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
diff --git a/nbformat/v1/nbjson.py b/nbformat/v1/nbjson.py
index aeb7b349..d319e60d 100644
--- a/nbformat/v1/nbjson.py
+++ b/nbformat/v1/nbjson.py
@@ -21,6 +21,7 @@
from .nbbase import from_dict
from .rwbase import NotebookReader, NotebookWriter
+
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
diff --git a/nbformat/v2/convert.py b/nbformat/v2/convert.py
index 501b90f6..dd3ab798 100644
--- a/nbformat/v2/convert.py
+++ b/nbformat/v2/convert.py
@@ -19,6 +19,7 @@
from .nbbase import new_code_cell, new_notebook, new_text_cell, new_worksheet
+
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
diff --git a/nbformat/v2/nbbase.py b/nbformat/v2/nbbase.py
index bc9f3ab4..72cf751f 100644
--- a/nbformat/v2/nbbase.py
+++ b/nbformat/v2/nbbase.py
@@ -23,6 +23,7 @@
from .._struct import Struct
+
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
diff --git a/nbformat/v2/nbjson.py b/nbformat/v2/nbjson.py
index 02eff5ba..59397333 100644
--- a/nbformat/v2/nbjson.py
+++ b/nbformat/v2/nbjson.py
@@ -20,13 +20,8 @@
import json
from .nbbase import from_dict
-from .rwbase import (
- NotebookReader,
- NotebookWriter,
- rejoin_lines,
- restore_bytes,
- split_lines,
-)
+from .rwbase import NotebookReader, NotebookWriter, rejoin_lines, restore_bytes, split_lines
+
# -----------------------------------------------------------------------------
# Code
diff --git a/nbformat/v2/rwbase.py b/nbformat/v2/rwbase.py
index edfc8deb..af23ade5 100644
--- a/nbformat/v2/rwbase.py
+++ b/nbformat/v2/rwbase.py
@@ -18,6 +18,7 @@
from base64 import decodebytes, encodebytes
+
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
diff --git a/nbformat/v3/nbjson.py b/nbformat/v3/nbjson.py
index 341e3e1c..f6efe8bb 100644
--- a/nbformat/v3/nbjson.py
+++ b/nbformat/v3/nbjson.py
@@ -7,13 +7,7 @@
import json
from .nbbase import from_dict
-from .rwbase import (
- NotebookReader,
- NotebookWriter,
- rejoin_lines,
- split_lines,
- strip_transient,
-)
+from .rwbase import NotebookReader, NotebookWriter, rejoin_lines, split_lines, strip_transient
class BytesEncoder(json.JSONEncoder):
diff --git a/nbformat/v4/nbjson.py b/nbformat/v4/nbjson.py
index 4b5c5642..70566749 100644
--- a/nbformat/v4/nbjson.py
+++ b/nbformat/v4/nbjson.py
@@ -7,13 +7,7 @@
import json
from ..notebooknode import from_dict
-from .rwbase import (
- NotebookReader,
- NotebookWriter,
- rejoin_lines,
- split_lines,
- strip_transient,
-)
+from .rwbase import NotebookReader, NotebookWriter, rejoin_lines, split_lines, strip_transient
class BytesEncoder(json.JSONEncoder):
diff --git a/nbformat/validator.py b/nbformat/validator.py
index 901d4fd0..ede37484 100644
--- a/nbformat/validator.py
+++ b/nbformat/validator.py
@@ -417,14 +417,14 @@ def validate(
version : int
version_minor : int
relax_add_props : bool
- Deprecated since 5.5.0 – will be removed in the future.
+ Deprecated since 5.5.0 - will be removed in the future.
Wether to allow extra property in the Json schema validating the
notebook.
nbjson
repair_duplicate_cell_ids : boolny
- Deprecated since 5.5.0 – will be removed in the future.
+ Deprecated since 5.5.0 - will be removed in the future.
strip_invalid_metadata : bool
- Deprecated since 5.5.0 – will be removed in the future.
+ Deprecated since 5.5.0 - will be removed in the future.
Returns
-------
diff --git a/pyproject.toml b/pyproject.toml
index 702917cd..fedd5e69 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -49,12 +49,13 @@ docs = [
"sphinxcontrib_github_alt"
]
test = [
- "check-manifest",
"testpath",
"pytest",
"pre-commit",
"pep440"
]
+lint = ["black[jupyter]>=22.6.0", "mdformat>0.7", "ruff>=0.0.156"]
+typing = ["mypy>=0.990"]
[project.scripts]
jupyter-trust = "nbformat.sign:TrustNotebookApp.launch_instance"
@@ -80,11 +81,24 @@ dependencies = ["coverage", "pytest-cov"]
test = "python -m pytest -vv --cov nbformat --cov-branch --cov-report term-missing:skip-covered {args}"
nowarn = "test -W default {args}"
-[tool.black]
-line_length = 100
-
-[tool.isort]
-profile = "black"
+[tool.hatch.envs.typing]
+features = ["typing", "test"]
+[tool.hatch.envs.typing.scripts]
+test = "mypy --install-types --non-interactive {args:nbformat tests}"
+
+[tool.hatch.envs.lint]
+features = ["lint"]
+[tool.hatch.envs.lint.scripts]
+style = [
+ "ruff {args:.}",
+ "black --check --diff {args:.}",
+ "mdformat --check {args:*.md}"
+]
+fmt = [
+ "black {args:.}",
+ "ruff --fix {args:.}",
+ "mdformat {args:*.md}"
+]
[tool.pytest.ini_options]
addopts = "-raXs --durations 10 --color=yes --doctest-modules"
@@ -133,26 +147,65 @@ module = [
]
ignore_missing_imports = true
-[tool.flake8]
-ignore = "E501, W503, E402"
-builtins = "c, get_config"
-exclude = [
- ".cache",
- ".github",
- "docs",
- "setup.py",
+[tool.black]
+line-length = 100
+skip-string-normalization = true
+target-version = ["py38"]
+extend-exclude = "^/tests.*ipynb$"
+
+[tool.ruff]
+target-version = "py38"
+line-length = 100
+select = [
+ "A", "B", "C", "E", "F", "FBT", "I", "N", "Q", "RUF", "S", "T",
+ "UP", "W", "YTT",
]
-enable-extensions = "G"
-extend-ignore = [
- "G001", "G002", "G004", "G200", "G201", "G202",
- # black adds spaces around ':'
- "E203",
+ignore = [
+ # Allow non-abstract empty methods in abstract base classes
+ "B027",
+ # Ignore McCabe complexity
+ "C901",
+ # Allow boolean positional values in function calls, like `dict.get(... True)`
+ "FBT003",
+ # Use of `assert` detected
+ "S101",
+ # Line too long
+ "E501",
+ # Relative imports are banned
+ "I252",
+ # Boolean ... in function definition
+ "FBT001", "FBT002",
+ # Module level import not at top of file
+ "E402",
+ # A001/A002/A003 .. is shadowing a python builtin
+ "A001", "A002", "A003",
+ # Possible hardcoded password
+ "S105", "S106",
+ # Q000 Single quotes found but double quotes preferred
+ "Q000",
+ # N806 Variable `B` in function should be lowercase
+ "N806",
+ # T201 `print` found
+ "T201",
+ # N802 Function name `CreateWellKnownSid` should be lowercase
+ "N802", "N803"
]
-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
- # B007 Loop control variable 'foo' not used within the loop body
- "tests/*: B011", "F841", "B007",
- # F401 '.foo' imported but unused
- "nbformat/*/__init__.py: F401",
+unfixable = [
+ # Don't touch print statements
+ "T201",
+ # Don't touch noqa lines
+ "RUF100",
]
+
+[tool.ruff.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 '-'?)
+"tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802", "RUF001", "RUF002"]
+# F401 `nbxml.to_notebook` imported but unused
+"nbformat/*__init__.py" = ["F401"]
diff --git a/tests/invalid.ipynb b/tests/invalid.ipynb
index e53a2df0..2435c06e 100644
--- a/tests/invalid.ipynb
+++ b/tests/invalid.ipynb
@@ -72,12 +72,15 @@
],
"source": [
"from IPython.display import HTML\n",
- "HTML(\"\"\"\n",
+ "\n",
+ "HTML(\n",
+ " \"\"\"\n",
"\n",
"HTML\n",
- "\"\"\")"
+ "\"\"\"\n",
+ ")"
]
},
{
@@ -296,6 +299,7 @@
],
"source": [
"from IPython.display import Image\n",
+ "\n",
"Image(\"http://ipython.org/_static/IPy_header.png\")"
]
}
diff --git a/tests/test4.5.ipynb b/tests/test4.5.ipynb
index ba09ecbd..076be786 100644
--- a/tests/test4.5.ipynb
+++ b/tests/test4.5.ipynb
@@ -76,12 +76,15 @@
],
"source": [
"from IPython.display import HTML\n",
- "HTML(\"\"\"\n",
+ "\n",
+ "HTML(\n",
+ " \"\"\"\n",
"\n",
"HTML\n",
- "\"\"\")"
+ "\"\"\"\n",
+ ")"
]
},
{
@@ -136,6 +139,7 @@
],
"source": [
"from IPython.display import Image\n",
+ "\n",
"Image(\"http://ipython.org/_static/IPy_header.png\")"
]
}
diff --git a/tests/test4.ipynb b/tests/test4.ipynb
index 20afe94d..7231e3a0 100644
--- a/tests/test4.ipynb
+++ b/tests/test4.ipynb
@@ -74,12 +74,15 @@
],
"source": [
"from IPython.display import HTML\n",
- "HTML(\"\"\"\n",
+ "\n",
+ "HTML(\n",
+ " \"\"\"\n",
"\n",
"HTML\n",
- "\"\"\")"
+ "\"\"\"\n",
+ ")"
]
},
{
@@ -298,6 +301,7 @@
],
"source": [
"from IPython.display import Image\n",
+ "\n",
"Image(\"http://ipython.org/_static/IPy_header.png\")"
]
}
diff --git a/tests/test4custom.ipynb b/tests/test4custom.ipynb
index 31fa9b11..68a0da91 100644
--- a/tests/test4custom.ipynb
+++ b/tests/test4custom.ipynb
@@ -26,11 +26,7 @@
"import IPython\n",
"\n",
"bundle = {}\n",
- "bundle['application/vnd.raw.v1+json'] = {\n",
- " 'apples': ['🍎', '🍏'],\n",
- " 'bananas': 2,\n",
- " 'oranges': 'apples'\n",
- "}\n",
+ "bundle['application/vnd.raw.v1+json'] = {'apples': ['🍎', '🍏'], 'bananas': 2, 'oranges': 'apples'}\n",
"\n",
"IPython.display.display(bundle, raw=True)"
]
@@ -45,8 +41,7 @@
"source": []
}
],
- "metadata": {
- },
+ "metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}
diff --git a/tests/test4docinfo.ipynb b/tests/test4docinfo.ipynb
index 7c308921..e0bb9f3d 100644
--- a/tests/test4docinfo.ipynb
+++ b/tests/test4docinfo.ipynb
@@ -74,12 +74,15 @@
],
"source": [
"from IPython.display import HTML\n",
- "HTML(\"\"\"\n",
+ "\n",
+ "HTML(\n",
+ " \"\"\"\n",
"\n",
"HTML\n",
- "\"\"\")"
+ "\"\"\"\n",
+ ")"
]
},
{
@@ -298,13 +301,18 @@
],
"source": [
"from IPython.display import Image\n",
+ "\n",
"Image(\"http://ipython.org/_static/IPy_header.png\")"
]
}
],
"metadata": {
- "title": "Test Notebook",
- "authors": [{"name": "Jean Tester"}]
+ "title": "Test Notebook",
+ "authors": [
+ {
+ "name": "Jean Tester"
+ }
+ ]
},
"nbformat": 4,
"nbformat_minor": 0
diff --git a/tests/test4jupyter_metadata_timings.ipynb b/tests/test4jupyter_metadata_timings.ipynb
index 2e724a55..96b01e7b 100644
--- a/tests/test4jupyter_metadata_timings.ipynb
+++ b/tests/test4jupyter_metadata_timings.ipynb
@@ -25,7 +25,7 @@
}
],
"source": [
- "1+1"
+ "1 + 1"
]
},
{
diff --git a/tests/test4plus.ipynb b/tests/test4plus.ipynb
index 522df071..2b61a123 100644
--- a/tests/test4plus.ipynb
+++ b/tests/test4plus.ipynb
@@ -84,12 +84,15 @@
],
"source": [
"from IPython.display import HTML\n",
- "HTML(\"\"\"\n",
+ "\n",
+ "HTML(\n",
+ " \"\"\"\n",
"\n",
"HTML\n",
- "\"\"\")"
+ "\"\"\"\n",
+ ")"
]
},
{
@@ -313,6 +316,7 @@
],
"source": [
"from IPython.display import Image\n",
+ "\n",
"Image(\"http://ipython.org/_static/IPy_header.png\")"
]
},
diff --git a/tests/test_reader.py b/tests/test_reader.py
index 4f3e2f5f..fbdf99f6 100644
--- a/tests/test_reader.py
+++ b/tests/test_reader.py
@@ -17,6 +17,7 @@
from .base import TestsBase
+
# -----------------------------------------------------------------------------
# Classes and functions
# -----------------------------------------------------------------------------