-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
[tests] Implementation of the new testing plugin (backward-compatible) [part 2] #12093
Open
picnixz
wants to merge
78
commits into
sphinx-doc:master
Choose a base branch
from
picnixz:core/test-plugin
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
78 commits
Select commit
Hold shift + click to select a range
a4ef0a5
patch marker signatures
picnixz 793f45c
update doc
picnixz 4bc677f
revert suppression
picnixz c69f375
add xdist dependency but disable it for now
picnixz 02e7813
Merge branch 'master' into fix/testing-types
picnixz 42f6044
fixup
picnixz e17f0b7
Merge branch 'fix/testing-types' into core/test-plugin
picnixz b5457e8
implement new plugin
picnixz 550a30f
fixup
picnixz 2235e7f
fixup
picnixz c8ffbd8
try to fix windows
picnixz 2b372cc
fixup
picnixz 866059e
fixup?
picnixz 9ee89b4
fixup
picnixz 100f861
fix a check + test
picnixz 30b82d7
Merge branch 'master' into fix/testing-types
picnixz 875ef51
fixup
picnixz bc00228
make the plugin backwards compatible
picnixz 4ce0115
Merge branch 'master' into core/test-plugin
picnixz 504bf49
Merge branch 'master' into fix/testing-types
picnixz 6f21442
ensure type safety
picnixz 6789bc3
allow buildername as a keyword argument in the marker
picnixz 333aa8f
allow buildername as a keyword argument in the marker
picnixz 91b035f
allow buildername as a keyword argument in the marker
picnixz 1aaa037
fix deprecation warning
picnixz 42e27f0
revert some changes
picnixz beb9c1e
revert some changes
picnixz 4d7172a
cleanup and simplify
picnixz 33d5772
cleanup and simplify
picnixz 5be3c74
remove xdist for now
picnixz b4f43ee
cleanup
picnixz fe89013
Merge branch 'master' into fix/testing-types
picnixz a93efe4
revert some changes
picnixz 6c45a41
remove ref
picnixz f60e97e
revert order
picnixz ba61814
Merge branch 'fix/testing-types' into core/test-plugin
picnixz cd94c8f
Merge branch 'master' into core/test-plugin
picnixz 54e394f
Merge branch 'master' into core/test-plugin
picnixz dce556d
fixup
picnixz a880fd0
use private naming
picnixz b5faf40
Merge branch 'master' into core/test-plugin
picnixz 6b43a6a
Refine configuration checksum
picnixz f7d7b73
Refine configuration checksum
picnixz d312815
fixup
picnixz 318e075
Merge branch 'master' into core/test-plugin
picnixz 4e06556
fixup
picnixz 33d48f7
Merge branch 'master' into core/test-plugin
picnixz 0da65df
update comment
picnixz f2e1044
Merge branch 'master' into core/test-plugin
picnixz 31e61b5
fixup isolation deduction
picnixz 86de828
fixup isolation deduction
picnixz 329b98b
cleanup
picnixz 2a5d03a
apply ruff format
picnixz 455b97d
Merge branch 'master' into core/test-plugin
picnixz e33ba40
fixup
picnixz 847eb7a
Merge branch 'master' into core/test-plugin
picnixz f787670
Merge branch 'master' into core/test-plugin
picnixz a257ec2
Merge branch 'master' into core/test-plugin
picnixz a7e4026
fix lint
picnixz da6e9c5
Merge branch 'master' into core/test-plugin
picnixz 054cb79
fix lint
picnixz e859d9f
Merge branch 'master' into core/test-plugin
picnixz f68197b
fixup
picnixz d71fdf5
Merge remote-tracking branch 'upstream/master' into core/test-plugin
picnixz e431ce9
cleanup
picnixz 74d96a3
cleanup
picnixz 9560a65
cleanup
picnixz a452a03
Merge branch 'master' into core/test-plugin
picnixz 9ca2a3b
Merge branch 'master' into core/test-plugin
picnixz 4f86bc8
Merge branch 'master' into core/test-plugin
picnixz 32fd55e
Merge remote-tracking branch 'upstream/master' into core/test-plugin
picnixz 588871e
update conftests
picnixz 4ec3e12
update conftests
picnixz acfcf5f
lint
picnixz 53585ab
Merge branch 'master' into core/test-plugin
picnixz 917307a
revert some changes
picnixz c997def
fix tests
picnixz f8f760f
fix lint
picnixz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
"""This package contains implementation details for the Sphinx testing plugin. | ||
|
||
All modules in this package are considered an implementation detail | ||
and any provided functionality can be altered, removed or introduce | ||
breaking changes without prior notice. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
from __future__ import annotations | ||
|
||
__all__ = () | ||
|
||
import dataclasses | ||
import itertools | ||
import shutil | ||
from io import StringIO | ||
from typing import TYPE_CHECKING, TypedDict | ||
|
||
if TYPE_CHECKING: | ||
from typing import Any | ||
|
||
from sphinx.testing.util import SphinxTestApp, SphinxTestAppWrapperForSkipBuilding | ||
|
||
|
||
class _CacheEntry(TypedDict): | ||
"""Cached entry in a :class:`ModuleCache`.""" | ||
|
||
status: str | ||
"""The application's status output.""" | ||
warning: str | ||
"""The application's warning output.""" | ||
|
||
|
||
class _CacheFrame(TypedDict): | ||
"""The restored cached value.""" | ||
|
||
status: StringIO | ||
"""An I/O object initialized to the cached status output.""" | ||
warning: StringIO | ||
"""An I/O object initialized to the cached warning output.""" | ||
|
||
|
||
class ModuleCache: | ||
__slots__ = ('_cache',) | ||
|
||
def __init__(self) -> None: | ||
self._cache: dict[str, _CacheEntry] = {} | ||
|
||
def clear(self) -> None: | ||
"""Clear the cache.""" | ||
self._cache.clear() | ||
|
||
def store(self, key: str, app: SphinxTestApp) -> None: | ||
"""Cache some attributes from *app* in the cache. | ||
|
||
:param key: The cache key (usually a ``shared_result``). | ||
:param app: An application whose attributes are cached. | ||
|
||
The application's attributes being cached are: | ||
|
||
* The content of :attr:`~sphinx.testing.util.SphinxTestApp.status`. | ||
* The content of :attr:`~sphinx.testing.util.SphinxTestApp.warning`. | ||
""" | ||
if key not in self._cache: | ||
status, warning = app.status.getvalue(), app.warning.getvalue() | ||
self._cache[key] = {'status': status, 'warning': warning} | ||
|
||
def restore(self, key: str) -> _CacheFrame | None: | ||
"""Reconstruct the cached attributes for *key*.""" | ||
if key not in self._cache: | ||
return None | ||
|
||
data = self._cache[key] | ||
return {'status': StringIO(data['status']), 'warning': StringIO(data['warning'])} | ||
|
||
|
||
@dataclasses.dataclass | ||
class AppInfo: | ||
"""Information to report during the teardown phase of the ``app()`` fixture. | ||
|
||
The information is either rendered as a report section (for ``xdist`` | ||
integration) or directly printed using a ``print`` statement. | ||
""" | ||
|
||
builder: str | ||
"""The builder name.""" | ||
|
||
testroot_path: str | None | ||
"""The absolute path to the sources directory (if any).""" | ||
shared_result: str | None | ||
"""The user-defined shared result (if any).""" | ||
|
||
srcdir: str | ||
"""The absolute path to the application's sources directory.""" | ||
outdir: str | ||
"""The absolute path to the application's output directory.""" | ||
|
||
extras: dict[str, Any] = dataclasses.field(default_factory=dict, init=False) | ||
"""Attributes added by :func:`sphinx.testing.fixtures.app_test_info`.""" | ||
|
||
# fields below are updated when tearing down :func:`sphinx.testing.fixtures.app` | ||
_messages: str = dataclasses.field(default='', init=False) | ||
"""The application's status messages (updated by the fixture).""" | ||
_warnings: str = dataclasses.field(default='', init=False) | ||
"""The application's warnings messages (updated by the fixture).""" | ||
|
||
def update(self, app: SphinxTestApp | SphinxTestAppWrapperForSkipBuilding) -> None: | ||
"""Update the application's status and warning messages.""" | ||
self._messages = app.status.getvalue() | ||
self._warnings = app.warning.getvalue() | ||
|
||
def render(self, nodeid: str | None = None) -> str: | ||
"""Format the report as a string to print or render. | ||
|
||
:param nodeid: Optional node id to include in the report. | ||
:return: The formatted information. | ||
""" | ||
config = [('builder', self.builder)] | ||
if nodeid: | ||
config.insert(0, ('test case', nodeid)) | ||
|
||
if self.testroot_path: | ||
config.append(('testroot path', self.testroot_path)) | ||
config.extend([('srcdir', self.srcdir), ('outdir', self.outdir)]) | ||
config.extend((name, repr(value)) for name, value in self.extras.items()) | ||
|
||
tw, _ = shutil.get_terminal_size() | ||
kw = 8 + max(len(name) for name, _ in config) | ||
|
||
lines = itertools.chain( | ||
[f'{" environment ":-^{tw}}'], | ||
(f'{name:{kw}s} {strvalue}' for name, strvalue in config), | ||
[f'{" messages ":-^{tw}}', text] if (text := self._messages) else (), | ||
[f'{" warnings ":-^{tw}}', text] if (text := self._warnings) else (), | ||
['=' * tw], | ||
) | ||
return '\n'.join(lines) | ||
|
||
|
||
# XXX: RemovedInSphinx90Warning | ||
class LegacyModuleCache: # kept for legacy purposes | ||
cache: dict[str, dict[str, str]] = {} | ||
|
||
def store( | ||
self, key: str, app_: SphinxTestApp | SphinxTestAppWrapperForSkipBuilding | ||
) -> None: | ||
if key in self.cache: | ||
return | ||
data = { | ||
'status': app_.status.getvalue(), | ||
'warning': app_.warning.getvalue(), | ||
} | ||
self.cache[key] = data | ||
|
||
def restore(self, key: str) -> dict[str, StringIO]: | ||
if key not in self.cache: | ||
return {} | ||
|
||
data = self.cache[key] | ||
return { | ||
'status': StringIO(data['status']), | ||
'warning': StringIO(data['warning']), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
"""Private module containing isolation-related objects and functionalities. | ||
|
||
Use literal strings or booleans to indicate isolation policies instead of | ||
directly using :class:`Isolation` objects, unless it is used internally. | ||
""" | ||
|
||
from __future__ import annotations | ||
|
||
__all__ = () | ||
|
||
from enum import IntEnum | ||
from enum import auto as _auto | ||
from typing import TYPE_CHECKING, Literal | ||
|
||
if TYPE_CHECKING: | ||
from typing import TypeAlias | ||
|
||
|
||
class Isolation(IntEnum): | ||
"""Isolation policy for the testing application.""" | ||
|
||
minimal = _auto() | ||
"""Minimal isolation mode.""" | ||
grouped = _auto() | ||
"""Similar to :attr:`always` but for parametrized tests.""" | ||
always = _auto() | ||
"""Copy the original testroot to a unique sources and build directory.""" | ||
|
||
|
||
IsolationPolicy: TypeAlias = bool | Literal['minimal', 'grouped', 'always'] | ||
"""Allowed values for the isolation policy.""" | ||
|
||
NormalizableIsolation: TypeAlias = IsolationPolicy | Isolation | ||
"""Normalizable isolation value.""" | ||
|
||
|
||
def normalize_isolation_policy(policy: NormalizableIsolation) -> Isolation: | ||
"""Normalize isolation policy into a :class:`Isolation` object.""" | ||
if isinstance(policy, Isolation): | ||
return policy | ||
|
||
if isinstance(policy, bool): | ||
return Isolation.always if policy else Isolation.minimal | ||
|
||
if isinstance(policy, str) and hasattr(Isolation, policy): | ||
return getattr(Isolation, policy) | ||
|
||
msg = f'unknown isolation policy: {policy!r}' | ||
raise TypeError(msg) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the caching functionality here (either the legacy caching, or the more modern alternative) used in the codebase yet? I couldn't find references to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be used somewhere unless I messed up the conflicts resolution.... I'll check it upon my return.