Notices
The point of this plugin is ultimately to compare the output of some static type checking tool against some known input and assert it matches some expected output.
That output can be thought of as a sequence of what this plugin calls “notices” that represent information about specific lines in specific files.
This plugin has a hierarchy to represent all those notices;
Note
There are notice_changers for modifying notices instead of directly accessing the api on the notices themselves
The pytest_typing_runner.protocols.ProgramNotice has on it the file
location, the line number, an optional column number, a severity, and a message.
Severities are currently modelled as a pytest_typing_runner.protocols.Severity
object with three default implementations:
- class pytest_typing_runner.notices.NoteSeverity
Represents a “note” severity
Implements
pytest_typing_runner.protocols.Severity
- class pytest_typing_runner.notices.WarningSeverity
Represents a “warning” severity
Implements
pytest_typing_runner.protocols.Severity
- class pytest_typing_runner.notices.ErrorSeverity(error_type: str)
Represents an “error” severity with an error type
The display will be
error[ERROR_TYPE]and comparisons/ordering will take theerror_typeinto account.Note that if the
error_typeis an empty string that comparisons with other severities will match anyerror_type.Implements
pytest_typing_runner.protocols.Severity- Parameters:
error_type – The specific type of error. For example
arg-typeorassignment
These are the default implementations of the different layers of the notices:
- class pytest_typing_runner.notices.ProgramNotice(*, location: Path, line_number: int, col: int | None, severity: Severity, msg: NoticeMsg)
Represents a single notice from the static type checker
Implements
pytest_typing_runner.protocols.ProgramNotice- Parameters:
location – The full path to the file this notice is for
line_number – the line this notice appears on
col – optional line representing the column the error relates to
severity – The severity of the notice (either note or error with a specific error type)
msg – The message in the notice
- classmethod reveal_msg(revealed: str, /) str
Helper to get a string that represents the
msgon a note for areveal_type(...)instruction
- property is_type_reveal: bool
Returns whether this notice represents output from a reveal_type(…) instruction
- clone(*, msg: str | NoticeMsg | None = None, **kwargs: Unpack[ProgramNoticeCloneKwargs]) Self
Return a copy of this notice with certain values replaced.
- display() str
Return a string for displaying this notice.
If
colis None then it’s not displayed.Will return “col=COL severity=SEVERITY:: MSG”
- matches(other: ProgramNotice) bool
Compare against another program notice.
If
colisNoneon either notice then that is not compared.
- class pytest_typing_runner.notices.LineNotices(location: Path, line_number: int)
This represents the notices at a specific line in a specific file
Implements
pytest_typing_runner.protocols.LineNotices- Parameters:
location – The path these notices are for
line_number – The specific line number for these notices
- classmethod msg_maker(*, pattern: str) Self
Used to construct a GlobMsg
Implements
NoticeMsgMaker
- property has_notices: bool
Return whether this contains any notices
- set_notices(notices: Sequence[ProgramNotice | None], allow_empty: Literal[True]) Self
- set_notices(notices: Sequence[ProgramNotice | None], allow_empty: Literal[False] = False) Self | None
Return a copy where the chosen notice(s) are replaced
- Parameters:
notices – The notices the clone should have. Any None entries are dropped
allow_empty – If False then None is returned instead of a copy with an empty list
- generate_notice(*, msg: str | NoticeMsg, msg_maker: NoticeMsgMaker | None = None, severity: Severity | None = None, col: int | None = None) ProgramNotice
Return an object that satisfies
pytest_typing_runner.protocols.ProgramNotice- Parameters:
severity – optional severity, defaults to “note”
msg – optional msg, defaults to an empty string
col – optional column, defaults to
None
- class pytest_typing_runner.notices.FileNotices(location: Path)
Used to represent the notices for a file
Implements
pytest_typing_runner.protocols.FileNotices- Parameters:
location – The location of the file the notices are in
- classmethod msg_maker(*, pattern: str) Self
Used to construct a GlobMsg
Implements
NoticeMsgMaker
- property has_notices: bool
Return True if there are there any notices for this file
- known_line_numbers() Iterator[int]
Yield the line numbers that have line notices
- property known_names: Mapping[str, int]
Return the registered names
- get_line_number(name_or_line: str | int, /) int | None
Normalise a name or line number to a line number.
The result has no relation to whether there are any notices for this file
- Parameters:
name_or_line –
When this is an integer it is returned as is regardless of whether it is named or has associated notices.
When it is a string, it will see if it is a registered name and either return
Noneif it is not registered, else return the associated line number.
- notices_at_line(line_number: int) LineNotices | None
Return
Noneif there are no line notices for that line number, else return the found line notices.Note that if there is an empty line notices that will be returned instead of None.
- generate_notices_for_line(line_number: int, *, msg_maker: NoticeMsgMaker | None = None) LineNotices
Return an object that satisfies
pytest_typing_runner.protocols.LineNoticesfor the location of this file at the specified line number.This object is not added to this file notices
- set_name(name: str, line_number: int) Self
Return a copy of the file notices with this
nameregistered for the specifiedline_number. If thenameis already registered it will be overridden.
- set_lines(notices: Mapping[int, LineNotices | None]) Self
Return a copy of this file notices with the notices replaced by those provided.
When the value is
Noneany notices for that line number will be removed.
- clear(*, clear_names: bool) Self
Return a modified file notices with all notices removed
- class pytest_typing_runner.notices.ProgramNotices
Represents all the notices for a run of a static type checker
Implements
pytest_typing_runner.protocols.ProgramNotices- classmethod msg_maker(*, pattern: str) Self
Used to construct a GlobMsg
Implements
NoticeMsgMaker
- property has_notices: bool
Return whether there are any notices
- known_locations() Iterator[Path]
Yield locations that have associated file notices
- diff(root_dir: Path, other: ProgramNotices) DiffNotices
Produce a diff where this program notices is on the left, and the notices passed in is on the right.
All locations across both will appear in the diff as strings relative to the passed in
root_dir.- Parameters:
root_dir – All locations will be represented as a string relative to the
root_direxcept for paths outside ofroot_dirwhich will be a string of the full pathother – The right side of the diff
- notices_at_location(location: Path) FileNotices | None
Return the FileNotices for the specified
locationorNoneif no existing notices for that location.Note if there is an empty FileNotices for that location it will be returned instead of
None- Parameters:
location – The location to return notices for
- generate_notices_for_location(location: Path, *, msg_maker: NoticeMsgMaker | None = None) FileNotices
Return an object that satisfies
pytest_typing_runner.protocols.FileNoticesNote the file notices are not added to this ProgramNotices.
- Parameters:
location – The value set on the FileNotices for
location
- set_files(notices: Mapping[Path, FileNotices | None]) Self
Return a copy of this ProgramNotices overriding the notices with those passed in
Note that
Nonevalues will result in that location being removed.Locations that exist but aren’t in the passed in notices will be preserved
- Parameters:
notices – A map of location to either FileNotices to set for that location or
Nonewhen that location should be removed.
The msg on a ProgramNotice
The msg property on a pytest_typing_runner.notices.ProgramNotice
is an object that has individual control over how it’s compared to other messages.
This means that one msg may compare itself to another using a regular
expression, whereas one may compare itself using a glob. The most common will
be a plain equality check.
The default implementations are:
- class pytest_typing_runner.notices.PlainMsg(raw: str, /)
A notice msg that compares by treating the msg as a plain string
from pytest_typing_runner import notices msg = notices.PlainMsg.create(pattern='Revealed type is "stuff"')
- classmethod create(*, pattern: str) Self
Used to construct a GlobMsg
Implements
NoticeMsgMaker
- match(*, want: str) bool
Returns whether this msg exactly matches the wanted string.
- clone(*, pattern: str) Self
Returns an instance of PlainMsg using the provided
pattern
- class pytest_typing_runner.notices.RegexMsg(raw: str, /)
A notice msg that compares by treating the msg as a regex pattern
from pytest_typing_runner import notices msg = notices.RegexMsg.create(pattern='Revealed type is "[^"]+"')
- classmethod create(*, pattern: str) Self
Used to construct a RegexMsg
Implements
NoticeMsgMaker
- match(*, want: str) bool
Returns whether this msg successfully performs a regex match on the wanted string.
- clone(*, pattern: str) Self
Returns an instance of RegexMsg using the provided
pattern
- class pytest_typing_runner.notices.GlobMsg(raw: str, /)
A notice msg that compares by treating the msg as a glob pattern
from pytest_typing_runner import notices msg = notices.RegexMsg.create(pattern='Revealed type is "*"')
- classmethod create(*, pattern: str) Self
Used to construct a GlobMsg
Implements
NoticeMsgMaker
- match(*, want: str) bool
Returns whether this msg successfully performs a glob match on the wanted string.
- clone(*, pattern: str) Self
Returns an instance of GlobMsg using the provided
pattern
Most things should be using
pytest_typing_runner.protocols.ScenarioRunner.generate_program_notices
to create a pytest_typing_runner.protocols.ProgramNotices which in
turn uses the default_msg_maker on the ScenarioRunner and so that’s a
sensible place to change the default:
from pytest_typing_runner import scenarios, protocols
import pytest
class MyScenarioRunner(scenarios.ScenarioRunner[protocols.T_Scenario]):
default_msg_maker: protocols.NoticeMsgMaker = notices.RegexMsg.create
@pytest.fixture
def typing_scenario_runner_maker(
typing_scenario_maker: protocols.ScenarioMaker[protocols.T_Scenario],
) -> protocols.ScenarioRunnerMaker[protocols.T_Scenario]:
return MyScenarioRunner.create
The msg_maker will be passed down from ProgramNotices to FileNotices
to LineNotices when the generiate_* methods are used on these containers.
When generate_notice is used on a LineNotices it will use msg_maker
if msg is passed in as a string. Otherwise it will use the msg as is.