diff --git a/.flake8 b/.flake8 deleted file mode 100644 index c8d89a3..0000000 --- a/.flake8 +++ /dev/null @@ -1,10 +0,0 @@ -[flake8] -ban-relative-imports = true -inline-quotes = " -ignore = - # Barring function calls in default args. Ha, no. - B008, - # See https://github.com/PyCQA/flake8-bugbear/issues/131 - B306, - # (flake8 default) old PEP8 boolean operator line breaks - W503, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 750e1bb..e8f87e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,44 +2,37 @@ name: CI on: push: + branches-ignore: + - "wip*" + tags: + - "v*" pull_request: - release: - types: [published] schedule: # Daily at 3:11 - cron: "11 3 * * *" - -env: - PIP_DISABLE_PIP_VERSION_CHECK: "1" - PIP_NO_PYTHON_VERSION_WARNING: "1" + workflow_dispatch: jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - uses: pre-commit/action@v3.0.0 - list: runs-on: ubuntu-latest outputs: noxenvs: ${{ steps.noxenvs-matrix.outputs.noxenvs }} steps: - uses: actions/checkout@v4 - - name: Set up nox - uses: wntrblm/nox@2023.04.22 + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true - id: noxenvs-matrix run: | echo >>$GITHUB_OUTPUT noxenvs=$( - nox --list-sessions --json | jq '[.[].session]' + uvx nox --list-sessions --json | jq '[.[].session]' ) ci: needs: list runs-on: ${{ matrix.os }} + strategy: fail-fast: false matrix: @@ -60,17 +53,18 @@ jobs: uses: actions/setup-python@v5 with: python-version: | - 3.8 - 3.9 - 3.10 3.11 3.12 - pypy3.10 + 3.13 allow-prereleases: true - - name: Set up nox - uses: wntrblm/nox@2023.04.22 + + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + - name: Run nox - run: nox -s "${{ matrix.noxenv }}" + run: uvx nox -s "${{ matrix.noxenv }}" packaging: needs: ci @@ -78,26 +72,27 @@ jobs: environment: name: PyPI url: https://pypi.org/p/sphinx-json-schema-spec + permissions: contents: write id-token: write steps: - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 + - name: Set up uv + uses: astral-sh/setup-uv@v5 with: - python-version: "3.x" - - name: Install dependencies - run: python -m pip install build - - name: Create packages - run: python -m build . + enable-cache: true + + - name: Build our distributions + run: uv run --with 'build[uv]' -m build --installer=uv + - name: Publish to PyPI if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@release/v1 - name: Create a Release if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: files: | dist/* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f55a6e3..b29ea18 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-ast - id: check-docstring-first @@ -13,11 +13,16 @@ repos: - id: mixed-line-ending args: [--fix, lf] - id: trailing-whitespace + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.9.1" + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/PyCQA/isort - rev: 5.13.0 + rev: 5.13.2 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v4.0.0-alpha.4" + rev: "v4.0.0-alpha.8" hooks: - id: prettier diff --git a/docs/requirements.in b/docs/requirements.in index 2ff9d8d..b1df148 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -1,5 +1,8 @@ -file:.#egg=sphinx_json_schema_spec +file:. furo sphinx>=5.1 sphinxcontrib-spelling>5 sphinxext-opengraph + +# Until pyenchant/pyenchant#302 is released... +pyenchant>=3.3.0rc1 diff --git a/docs/requirements.txt b/docs/requirements.txt index 78120b6..abf36ac 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,79 +1,74 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --strip-extras docs/requirements.in -# -alabaster==0.7.13 +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file /Users/julian/Development/sphinx-json-schema-spec/docs/requirements.txt docs/requirements.in +alabaster==1.0.0 # via sphinx -babel==2.14.0 +babel==2.16.0 # via sphinx -beautifulsoup4==4.12.2 +beautifulsoup4==4.12.3 # via furo -certifi==2023.11.17 +certifi==2024.12.14 # via requests -charset-normalizer==3.3.2 +charset-normalizer==3.4.1 # via requests -docutils==0.20.1 +docutils==0.21.2 # via sphinx -furo==2023.9.10 +furo==2024.8.6 # via -r docs/requirements.in -idna==3.6 +idna==3.10 # via requests imagesize==1.4.1 # via sphinx -jinja2==3.1.2 +jinja2==3.1.5 # via sphinx -lxml==5.0.0 +lxml==5.3.0 # via sphinx-json-schema-spec -markupsafe==2.1.3 +markupsafe==3.0.2 # via jinja2 -packaging==23.2 +packaging==24.2 # via sphinx -pyenchant==3.2.2 - # via sphinxcontrib-spelling -pygments==2.17.2 +pyenchant==3.3.0rc1 + # via + # -r docs/requirements.in + # sphinxcontrib-spelling +pygments==2.19.1 # via # furo # sphinx -requests==2.31.0 - # via sphinx +requests==2.32.3 + # via + # sphinx + # sphinxcontrib-spelling snowballstemmer==2.2.0 # via sphinx -soupsieve==2.5 +soupsieve==2.6 # via beautifulsoup4 -sphinx==7.2.6 +sphinx==8.1.3 # via # -r docs/requirements.in # furo # sphinx-basic-ng # sphinx-json-schema-spec - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml # sphinxcontrib-spelling # sphinxext-opengraph sphinx-basic-ng==1.0.0b2 # via furo -file:.#egg=sphinx_json_schema_spec +sphinx-json-schema-spec @ file:. # via -r docs/requirements.in -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==2.0.0 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==2.0.0 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.1.0 # via sphinx sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==2.0.0 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==2.0.0 # via sphinx -sphinxcontrib-spelling==8.0.0 +sphinxcontrib-spelling==8.0.1 # via -r docs/requirements.in sphinxext-opengraph==0.9.1 # via -r docs/requirements.in -urllib3==2.1.0 +urllib3==2.3.0 # via requests diff --git a/noxfile.py b/noxfile.py index 85d9421..de5c55f 100644 --- a/noxfile.py +++ b/noxfile.py @@ -12,12 +12,13 @@ docs=DOCS / "requirements.txt", ) REQUIREMENTS_IN = [ # this is actually ordered, as files depend on each other - path.parent / f"{path.stem}.in" for path in REQUIREMENTS.values() + (path.parent / f"{path.stem}.in", path) for path in REQUIREMENTS.values() ] -SUPPORTED = ["3.11", "3.12"] -LATEST = "3.12" +SUPPORTED = ["3.11", "3.12", "3.13"] +LATEST = SUPPORTED[-1] +nox.options.default_venv_backend = "uv|virtualenv" nox.options.sessions = [] @@ -53,9 +54,15 @@ def build(session): """ Build a distribution suitable for PyPI and check its validity. """ - session.install("build", "twine") + session.install("build[uv]", "twine") with TemporaryDirectory() as tmpdir: - session.run("python", "-m", "build", ROOT, "--outdir", tmpdir) + session.run( + "pyproject-build", + "--installer=uv", + ROOT, + "--outdir", + tmpdir, + ) session.run("twine", "check", "--strict", tmpdir + "/*") @@ -130,15 +137,17 @@ def docs_style(session): @session(default=False) def requirements(session): """ - Update the project's pinned requirements. Commit the result. + Update the project's pinned requirements. + + You should commit the result afterwards. """ - session.install("pip-tools") - for each in REQUIREMENTS_IN: - session.run( - "pip-compile", - "--resolver", - "backtracking", - "--strip-extras", - "-U", - each.relative_to(ROOT), - ) + if session.venv_backend == "uv": + cmd = ["uv", "pip", "compile"] + else: + session.install("pip-tools") + cmd = ["pip-compile", "--resolver", "backtracking", "--strip-extras"] + + for each, out in REQUIREMENTS_IN: + # otherwise output files end up with silly absolute path comments... + relative = each.relative_to(ROOT) + session.run(*cmd, "--upgrade", "--output-file", out, relative) diff --git a/pyproject.toml b/pyproject.toml index a089c38..1fba154 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,20 +10,20 @@ name = "sphinx_json_schema_spec" description = "Sphinx support for the JSON Schema specifications" requires-python = ">=3.11" readme = "README.rst" -license = {text = "MIT"} +license = "MIT" +license-files = ["COPYING"] keywords = ["json schema", "jsonschema", "data validation", "sphinx", "json"] authors = [ - {email = "Julian+sphinx-json-schema-spec@GrayVines.com"}, - {name = "Julian Berman"}, + { name = "Julian Berman", email = "Julian+sphinx-json-schema-spec@GrayVines.com" }, ] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Framework :: Sphinx :: Extension", @@ -45,25 +45,20 @@ Source = "https://github.com/python-jsonschema/sphinx-json-schema-spec" [tool.doc8] ignore = [ - "D000", # see PyCQA/doc8#125 - "D001", # one sentence per line, so max length doesn't make sense + "D000", # see PyCQA/doc8#125 + "D001", # one sentence per line, so max length doesn't make sense ] -[tool.isort] -combine_as_imports = true -ensure_newline_before_comments = true -from_first = true -include_trailing_comma = true -multi_line_output = 3 -use_parentheses = true - [tool.ruff] line-length = 79 + +[tool.ruff.lint] select = ["ALL"] ignore = [ "A001", # It's fine to shadow builtins "A002", "A003", + "A005", "ARG", # This is all wrong whenever an interface is involved "ANN", # Just let the type checker do this "B006", # Mutable arguments require care but are OK if you don't abuse them @@ -86,7 +81,6 @@ ignore = [ "EM102", "FBT", # It's worth avoiding boolean args but I don't care to enforce it "FIX", # Yes thanks, if I could it wouldn't be there - "I001", # We can't yet use ruff's isort "N", # These naming rules are silly "PLR0912", # These metrics are fine to be aware of but not to enforce "PLR0913", @@ -104,19 +98,18 @@ ignore = [ "SLF001", # Private usage within this package itself is fine "TD", # These TODO style rules are also silly ] -extend-exclude = ["suite"] [tool.ruff.lint.flake8-pytest-style] mark-parentheses = false -[tool.ruff.flake8-quotes] +[tool.ruff.lint.flake8-quotes] docstring-quotes = "double" [tool.ruff.lint.isort] combine-as-imports = true from-first = true -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "noxfile.py" = ["ANN", "D100", "S101", "T201"] "docs/*" = ["ANN", "D", "INP001"] "sphinx_json_schema_spec/tests/*" = ["ANN", "D", "RUF012", "S", "PLR", "TRY"] diff --git a/sphinx_json_schema_spec/__init__.py b/sphinx_json_schema_spec/__init__.py index 87111b5..5212521 100644 --- a/sphinx_json_schema_spec/__init__.py +++ b/sphinx_json_schema_spec/__init__.py @@ -33,6 +33,7 @@ def setup(app): app (sphinx.application.Sphinx): the Sphinx application context + """ app.add_config_value("cache_path", "_cache", "") @@ -67,6 +68,7 @@ def fetch_or_load(cache_path, url): url: the URL of the document + """ version = metadata.version("sphinx-json-schema-spec") headers = {"User-Agent": f"sphinx-json-schema-spec v{version}"} @@ -130,6 +132,7 @@ def keyword(name, raw_text, text, lineno, inliner): a 2-tuple of nodes to insert into the document and an iterable of system messages, both possibly empty + """ hardcoded = HARDCODED.get(text) if hardcoded is not None: