Move `_file_checksum() to sphinx.builders.html._assets`

This commit is contained in:
Adam Turner 2023-08-12 00:20:00 +01:00
parent 44a7820cd9
commit 42a6546404
3 changed files with 36 additions and 27 deletions

View File

@ -9,7 +9,6 @@ import posixpath
import re import re
import sys import sys
import warnings import warnings
import zlib
from datetime import datetime, timezone from datetime import datetime, timezone
from os import path from os import path
from typing import IO, TYPE_CHECKING, Any from typing import IO, TYPE_CHECKING, Any
@ -27,6 +26,7 @@ from sphinx import __display_version__, package_dir
from sphinx import version_info as sphinx_version from sphinx import version_info as sphinx_version
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.builders.html._assets import _file_checksum
from sphinx.config import ENUM, Config from sphinx.config import ENUM, Config
from sphinx.domains import Domain, Index, IndexEntry from sphinx.domains import Domain, Index, IndexEntry
from sphinx.environment import BuildEnvironment from sphinx.environment import BuildEnvironment
@ -1254,29 +1254,6 @@ def setup_js_tag_helper(app: Sphinx, pagename: str, templatename: str,
context['js_tag'] = js_tag context['js_tag'] = js_tag
def _file_checksum(outdir: str | os.PathLike[str], filename: str | os.PathLike[str]) -> str:
filename = os.fspath(filename)
# Don't generate checksums for HTTP URIs
if '://' in filename:
return ''
# Some themes and extensions have used query strings
# for a similar asset checksum feature.
# As we cannot safely strip the query string,
# raise an error to the user.
if '?' in filename:
msg = f'Local asset file paths must not contain query strings: {filename!r}'
raise ThemeError(msg)
try:
# Ensure universal newline mode is used to avoid checksum differences
with open(path.join(outdir, filename), encoding='utf-8') as f:
content = f.read().encode(encoding='utf-8')
except FileNotFoundError:
return ''
if not content:
return ''
return f'{zlib.crc32(content):08x}'
def setup_resource_paths(app: Sphinx, pagename: str, templatename: str, def setup_resource_paths(app: Sphinx, pagename: str, templatename: str,
context: dict, doctree: Node) -> None: context: dict, doctree: Node) -> None:
"""Set up relative resource paths.""" """Set up relative resource paths."""

View File

@ -0,0 +1,32 @@
from __future__ import annotations
import os
import zlib
from typing import TYPE_CHECKING
from sphinx.errors import ThemeError
if TYPE_CHECKING:
from pathlib import Path
def _file_checksum(outdir: Path, filename: str | os.PathLike[str]) -> str:
filename = os.fspath(filename)
# Don't generate checksums for HTTP URIs
if '://' in filename:
return ''
# Some themes and extensions have used query strings
# for a similar asset checksum feature.
# As we cannot safely strip the query string,
# raise an error to the user.
if '?' in filename:
msg = f'Local asset file paths must not contain query strings: {filename!r}'
raise ThemeError(msg)
try:
# Remove all carriage returns to avoid checksum differences
content = outdir.joinpath(filename).read_bytes().translate(None, b'\r')
except FileNotFoundError:
return ''
if not content:
return ''
return f'{zlib.crc32(content):08x}'

View File

@ -12,10 +12,10 @@ from html5lib import HTMLParser
import sphinx.builders.html import sphinx.builders.html
from sphinx.builders.html import ( from sphinx.builders.html import (
_file_checksum,
validate_html_extra_path, validate_html_extra_path,
validate_html_static_path, validate_html_static_path,
) )
from sphinx.builders.html._assets import _file_checksum
from sphinx.errors import ConfigError, ThemeError from sphinx.errors import ConfigError, ThemeError
from sphinx.testing.util import strip_escseq from sphinx.testing.util import strip_escseq
from sphinx.util.inventory import InventoryFile from sphinx.util.inventory import InventoryFile
@ -1248,10 +1248,10 @@ def test_file_checksum(app):
def test_file_checksum_query_string(): def test_file_checksum_query_string():
with pytest.raises(ThemeError, match='Local asset file paths must not contain query strings'): with pytest.raises(ThemeError, match='Local asset file paths must not contain query strings'):
_file_checksum('', 'with_query_string.css?dead_parrots=1') _file_checksum(Path(), 'with_query_string.css?dead_parrots=1')
with pytest.raises(ThemeError, match='Local asset file paths must not contain query strings'): with pytest.raises(ThemeError, match='Local asset file paths must not contain query strings'):
_file_checksum('', 'with_query_string.js?dead_parrots=1') _file_checksum(Path(), 'with_query_string.js?dead_parrots=1')
with pytest.raises(ThemeError, match='Local asset file paths must not contain query strings'): with pytest.raises(ThemeError, match='Local asset file paths must not contain query strings'):
_file_checksum(Path.cwd(), '_static/with_query_string.css?dead_parrots=1') _file_checksum(Path.cwd(), '_static/with_query_string.css?dead_parrots=1')