Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_multi_line_copyright fails when SOURCE_DATE_EPOCH used #11514

Closed
polyzen opened this issue Jul 25, 2023 · 2 comments
Closed

test_multi_line_copyright fails when SOURCE_DATE_EPOCH used #11514

polyzen opened this issue Jul 25, 2023 · 2 comments

Comments

@polyzen
Copy link
Contributor

polyzen commented Jul 25, 2023

Describe the bug

test_multi_line_copyright fails when SOURCE_DATE_EPOCH used.

show/hide
_________________ ERROR at setup of test_multi_line_copyright __________________

self = <sphinx.events.EventManager object at 0x7fcc063dc5b0>
name = 'config-inited', allowed_exceptions = ()
args = (<sphinx.config.Config object at 0x7fcc063dfad0>,)
results = [None, None, None, None, None, None, ...]
listeners = [EventListener(id=0, handler=<function convert_epub_css_files at 0x7fcc08f903c0>, priority=800), EventListener(id=2, h...45700>, priority=800), EventListener(id=6, handler=<function validate_html_logo at 0x7fcc090457b0>, priority=800), ...]

    def emit(self, name: str, *args: Any,
             allowed_exceptions: tuple[type[Exception], ...] = ()) -> list:
        """Emit a Sphinx event."""
        try:
            logger.debug('[app] emitting event: %r%s', name, repr(args)[:100])
        except Exception:
            # not every object likes to be repr()'d (think
            # random stuff coming via autodoc)
            pass

        results = []
        listeners = sorted(self.listeners[name], key=attrgetter("priority"))
        for listener in listeners:
            try:
>               results.append(listener.handler(self.app, *args))

sphinx/events.py:96:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

app = <[AttributeError("'SphinxTestApp' object has no attribute 'builder'") raised in repr()] SphinxTestApp object at 0x7fcc05c12950>
config = <sphinx.config.Config object at 0x7fcc063dfad0>

    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)

        See https://reproducible-builds.org/specs/source-date-epoch/
        """
        if getenv('SOURCE_DATE_EPOCH') is not None:
            for k in ('copyright', 'epub_copyright'):
                if k in config:
                    replace = r'\g<1>%s' % format_date('%Y', language='en')
>                   config[k] = copyright_year_re.sub(replace, config[k])
E                   TypeError: expected string or bytes-like object, got 'tuple'

sphinx/config.py:430: TypeError

The above exception was the direct cause of the following exception:

test_params = {'shared_result': None}
app_params = app_params(args=[], kwargs={'srcdir': path('/tmp/pytest-of-builduser/pytest-0/copyright-multiline')})
make_app = <function make_app.<locals>.make at 0x7fcc04229a70>
shared_result = <sphinx.testing.fixtures.SharedResult object at 0x7fcc05c12ae0>

    @pytest.fixture(scope='function')
    def app(test_params: dict, app_params: tuple[dict, dict], make_app: Callable,
            shared_result: SharedResult) -> Generator[SphinxTestApp, None, None]:
        """
        Provides the 'sphinx.application.Sphinx' object
        """
        args, kwargs = app_params
>       app_ = make_app(*args, **kwargs)

sphinx/testing/fixtures.py:132:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
sphinx/testing/fixtures.py:178: in make
    app_: Any = SphinxTestApp(*args, **kwargs)
sphinx/testing/util.py:140: in __init__
    super().__init__(srcdir, confdir, outdir, doctreedir,
sphinx/application.py:253: in __init__
    self.events.emit('config-inited', self.config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <sphinx.events.EventManager object at 0x7fcc063dc5b0>
name = 'config-inited', allowed_exceptions = ()
args = (<sphinx.config.Config object at 0x7fcc063dfad0>,)
results = [None, None, None, None, None, None, ...]
listeners = [EventListener(id=0, handler=<function convert_epub_css_files at 0x7fcc08f903c0>, priority=800), EventListener(id=2, h...45700>, priority=800), EventListener(id=6, handler=<function validate_html_logo at 0x7fcc090457b0>, priority=800), ...]

    def emit(self, name: str, *args: Any,
             allowed_exceptions: tuple[type[Exception], ...] = ()) -> list:
        """Emit a Sphinx event."""
        try:
            logger.debug('[app] emitting event: %r%s', name, repr(args)[:100])
        except Exception:
            # not every object likes to be repr()'d (think
            # random stuff coming via autodoc)
            pass

        results = []
        listeners = sorted(self.listeners[name], key=attrgetter("priority"))
        for listener in listeners:
            try:
                results.append(listener.handler(self.app, *args))
            except allowed_exceptions:
                # pass through the errors specified as *allowed_exceptions*
                raise
            except SphinxError:
                raise
            except Exception as exc:
                if self.app.pdb:
                    # Just pass through the error, so that it can be debugged.
                    raise
                modname = safe_getattr(listener.handler, '__module__', None)
>               raise ExtensionError(__("Handler %r for event %r threw an exception") %
                                     (listener.handler, name), exc, modname=modname) from exc
E               sphinx.errors.ExtensionError: Handler <function correct_copyright_year at 0x7fcc09d02410> for event 'config-inited' threw an exception (exception: expected string or bytes-like object, got 'tuple')

sphinx/events.py:107: ExtensionError
=============================== warnings summary ===============================
tests/test_build_manpage.py::test_all
  /build/python-sphinx/src/sphinx-7.1.0/sphinx/application.py:314: ResourceWarning: unclosed <socket.socket fd=16, family=2, type=1, proto=6, laddr=('127.0.0.1', 48398), raddr=('127.0.0.1', 7777)>
    env = pickle.load(f)
  Enable tracemalloc to get traceback where the object was allocated.
  See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py::test_multi_line_copyright - sphinx.errors.Extensi...
======= 1898 passed, 11 skipped, 1 warning, 1 error in 162.31s (0:02:42) =======

How to Reproduce

SOURCE_DATE_EPOCH=$(date +%s) pytest tests/test_config.py::test_multi_line_copyright

Environment Information

`python -m sphinx --bug-report` run from 7.1.0 sources:


Platform:              linux; (Linux-6.4.4-arch1-1-x86_64-with-glibc2.37)
Python version:        3.11.3 (main, Jun  5 2023, 09:32:32) [GCC 13.1.1 20230429])
Python implementation: CPython
Sphinx version:        7.1.0
Docutils version:      0.20.1
Jinja2 version:        3.1.2
Pygments version:      2.15.1

Sphinx extensions

No response

Additional context

No response

@picnixz
Copy link
Member

picnixz commented Jul 25, 2023

The issue lies with sphinx.config.correct_copyright_year which when querying config['copyright'] actually gets a tuple instead of a string. Now, I am very confused because

SOURCE_DATE_EPOCH=$(date +%s) \
python3.10 -m tox -e py310 -- tests/test_config.py::test_multi_line_copyright

actually works. It appears that the environment variable is ignored when using tox and that's why developpers didn't detect the issue. I don't know how to patch it properly because config.copyright is actually allowed to be a tuple. My best shot is to actually replace all items in the copyright list using the same logic. I'll submit a patch today but I'll need some feedback (I never used a copyright consisting of multiple items).

@AA-Turner
Copy link
Member

Fixed in #11524.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants