mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Support placeholders for years in copyright (#12910)
This commit is contained in:
@@ -53,6 +53,12 @@ Features added
|
||||
GMT (universal time) instead of local time for the date-time
|
||||
supplied to :confval:`html_last_updated_fmt`.
|
||||
Patch by Adam Turner.
|
||||
* #12910: Copyright entries now support the ``'%Y'`` placeholder
|
||||
to substitute the current year.
|
||||
This is helpful for reducing the reliance on Python modules
|
||||
such as :py:mod:`time` or :py:mod:`datetime` in :file:`conf.py`.
|
||||
See :ref:`the docs <config-copyright>` for further detail.
|
||||
Patch by Adam Turner.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
@@ -3,7 +3,6 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sphinx import __display_version__
|
||||
@@ -27,7 +26,7 @@ templates_path = ['_templates']
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
project = 'Sphinx'
|
||||
copyright = f'2007-{time.strftime("%Y")}, the Sphinx developers'
|
||||
copyright = '2007-%Y, the Sphinx developers'
|
||||
release = version = __display_version__
|
||||
show_authors = True
|
||||
nitpicky = True
|
||||
|
||||
@@ -114,6 +114,8 @@ Project information
|
||||
|
||||
author = 'Joe Bloggs'
|
||||
|
||||
.. _config-copyright:
|
||||
|
||||
.. confval:: copyright
|
||||
project_copyright
|
||||
:type: :code-py:`str | Sequence[str]`
|
||||
@@ -128,6 +130,14 @@ Project information
|
||||
* :code-py:`copyright = 'YYYY-YYYY, Author Name'`
|
||||
* :code-py:`copyright = 'YYYY-YYYY Author Name'`
|
||||
|
||||
If the string :code-py:`'%Y'` appears in a copyright line,
|
||||
it will be replaced with the current four-digit year.
|
||||
For example:
|
||||
|
||||
* :code-py:`copyright = '%Y'`
|
||||
* :code-py:`copyright = '%Y, Author Name'`
|
||||
* :code-py:`copyright = 'YYYY-%Y, Author Name'`
|
||||
|
||||
.. versionadded:: 3.5
|
||||
The :code-py:`project_copyright` alias.
|
||||
|
||||
@@ -135,6 +145,9 @@ Project information
|
||||
The value may now be a sequence of copyright statements in the above form,
|
||||
which will be displayed each to their own line.
|
||||
|
||||
.. versionchanged:: 8.1
|
||||
Copyright statements support the :code-py:`'%Y'` placeholder.
|
||||
|
||||
.. confval:: version
|
||||
:type: :code-py:`str`
|
||||
:default: :code-py:`''`
|
||||
@@ -2528,6 +2541,7 @@ so the HTML options also apply where appropriate.
|
||||
:default: The value of **copyright**
|
||||
|
||||
The copyright of the document.
|
||||
See :confval:`copyright` for permitted formats.
|
||||
|
||||
.. confval:: epub_identifier
|
||||
:type: :code-py:`str`
|
||||
|
||||
@@ -619,6 +619,21 @@ def init_numfig_format(app: Sphinx, config: Config) -> None:
|
||||
config.numfig_format = numfig_format
|
||||
|
||||
|
||||
def evaluate_copyright_placeholders(_app: Sphinx, config: Config) -> None:
|
||||
"""Replace copyright year placeholders (%Y) with the current year."""
|
||||
replace_yr = str(time.localtime().tm_year)
|
||||
for k in ('copyright', 'epub_copyright'):
|
||||
if k in config:
|
||||
value: str | Sequence[str] = config[k]
|
||||
if isinstance(value, str):
|
||||
if '%Y' in value:
|
||||
config[k] = value.replace('%Y', replace_yr)
|
||||
else:
|
||||
if any('%Y' in line for line in value):
|
||||
items = (line.replace('%Y', replace_yr) for line in value)
|
||||
config[k] = type(value)(items) # type: ignore[call-arg]
|
||||
|
||||
|
||||
def correct_copyright_year(_app: Sphinx, config: Config) -> None:
|
||||
"""Correct values of copyright year that are not coherent with
|
||||
the SOURCE_DATE_EPOCH environment variable (if set)
|
||||
@@ -775,6 +790,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
app.connect('config-inited', convert_source_suffix, priority=800)
|
||||
app.connect('config-inited', convert_highlight_options, priority=800)
|
||||
app.connect('config-inited', init_numfig_format, priority=800)
|
||||
app.connect('config-inited', evaluate_copyright_placeholders, priority=795)
|
||||
app.connect('config-inited', correct_copyright_year, priority=800)
|
||||
app.connect('config-inited', check_confval_types, priority=800)
|
||||
app.connect('config-inited', check_primary_domain, priority=800)
|
||||
|
||||
@@ -4,7 +4,11 @@ import time
|
||||
|
||||
import pytest
|
||||
|
||||
from sphinx.config import Config, correct_copyright_year
|
||||
from sphinx.config import (
|
||||
Config,
|
||||
correct_copyright_year,
|
||||
evaluate_copyright_placeholders,
|
||||
)
|
||||
|
||||
LT = time.localtime()
|
||||
LT_NEW = (2009, *LT[1:], LT.tm_zone, LT.tm_gmtoff)
|
||||
@@ -106,6 +110,19 @@ def test_correct_year_single_no_author(expect_date):
|
||||
assert cfg.copyright == copyright_date
|
||||
|
||||
|
||||
def test_correct_year_placeholder(expect_date):
|
||||
# test that copyright is substituted
|
||||
copyright_date = '2006-%Y, Alice'
|
||||
cfg = Config({'copyright': copyright_date}, {})
|
||||
assert cfg.copyright == copyright_date
|
||||
evaluate_copyright_placeholders(None, cfg) # type: ignore[arg-type]
|
||||
correct_copyright_year(None, cfg) # type: ignore[arg-type]
|
||||
if expect_date and expect_date <= LOCALTIME_2009.tm_year:
|
||||
assert cfg.copyright == f'2006-{expect_date}, Alice'
|
||||
else:
|
||||
assert cfg.copyright == '2006-2009, Alice'
|
||||
|
||||
|
||||
def test_correct_year_multi_line(expect_date):
|
||||
# test that copyright is substituted
|
||||
copyright_dates = (
|
||||
@@ -159,6 +176,47 @@ def test_correct_year_multi_line_all_formats(expect_date):
|
||||
assert cfg.copyright == copyright_dates
|
||||
|
||||
|
||||
def test_correct_year_multi_line_all_formats_placeholder(expect_date):
|
||||
# test that copyright is substituted
|
||||
copyright_dates = (
|
||||
'%Y',
|
||||
'%Y Alice',
|
||||
'%Y, Bob',
|
||||
'2006-%Y',
|
||||
'2006-%Y Charlie',
|
||||
'2006-%Y, David',
|
||||
# other format codes are left as-is
|
||||
'2006-%y, Eve',
|
||||
'%Y-%m-%d %H:%M:S %z, Francis',
|
||||
)
|
||||
cfg = Config({'copyright': copyright_dates}, {})
|
||||
assert cfg.copyright == copyright_dates
|
||||
evaluate_copyright_placeholders(None, cfg) # type: ignore[arg-type]
|
||||
correct_copyright_year(None, cfg) # type: ignore[arg-type]
|
||||
if expect_date and expect_date <= LOCALTIME_2009.tm_year:
|
||||
assert cfg.copyright == (
|
||||
f'{expect_date}',
|
||||
f'{expect_date} Alice',
|
||||
f'{expect_date}, Bob',
|
||||
f'2006-{expect_date}',
|
||||
f'2006-{expect_date} Charlie',
|
||||
f'2006-{expect_date}, David',
|
||||
'2006-%y, Eve',
|
||||
'2009-%m-%d %H:%M:S %z, Francis',
|
||||
)
|
||||
else:
|
||||
assert cfg.copyright == (
|
||||
'2009',
|
||||
'2009 Alice',
|
||||
'2009, Bob',
|
||||
'2006-2009',
|
||||
'2006-2009 Charlie',
|
||||
'2006-2009, David',
|
||||
'2006-%y, Eve',
|
||||
'2009-%m-%d %H:%M:S %z, Francis',
|
||||
)
|
||||
|
||||
|
||||
def test_correct_year_app(expect_date, tmp_path, make_app):
|
||||
# integration test
|
||||
copyright_date = '2006-2009, Alice'
|
||||
Reference in New Issue
Block a user