diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2aec404af..e72e00087 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,6 +21,7 @@ repos: rev: "v0.0.292" hooks: - id: ruff + args: [--fix, --exit-non-zero-on-fix] - repo: local hooks: - id: check-dependabot diff --git a/.pre-commit-hooks/check-dependabot b/.pre-commit-hooks/check-dependabot index 765a2b7ba..521fd223b 100755 --- a/.pre-commit-hooks/check-dependabot +++ b/.pre-commit-hooks/check-dependabot @@ -10,7 +10,7 @@ from yaml import safe_load as loads ROOT = Path(__file__).absolute().parent.parent DEPENDABOT = ROOT.joinpath(".github/dependabot.yml").read_text() IMPLEMENTATIONS = ROOT / "implementations" -DEPENDABOT_DOCS = "https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem" # noqa: E501 +DEPENDABOT_DOCS = "https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem" # Every implementation must appear both for container image updates # (in the docker ecosystem) as well as for its own packaging ecosystem diff --git a/bowtie/_cli.py b/bowtie/_cli.py index 3a49ca65d..b6af1e9b5 100644 --- a/bowtie/_cli.py +++ b/bowtie/_cli.py @@ -98,8 +98,8 @@ _F = Literal["json", "pretty"] -@tui(help="Open a simple interactive TUI for executing Bowtie commands.") # type: ignore[reportGeneralTypeIssues] # noqa: E501 -@click.group(context_settings=dict(help_option_names=["--help", "-h"])) # type: ignore[reportUntypedFunctionDecorator] # noqa: E501 +@tui(help="Open a simple interactive TUI for executing Bowtie commands.") # type: ignore[reportGeneralTypeIssues] +@click.group(context_settings=dict(help_option_names=["--help", "-h"])) # type: ignore[reportUntypedFunctionDecorator] @click.version_option(prog_name="bowtie", package_name="bowtie-json-schema") def main(): """ @@ -162,9 +162,9 @@ def to_serializable( match format: case "json": - click.echo(json.dumps(to_serializable(results), indent=2)) # type: ignore[reportGeneralTypeIssues] # noqa: E501 + click.echo(json.dumps(to_serializable(results), indent=2)) # type: ignore[reportGeneralTypeIssues] case "pretty": - table = to_table(summary, results) # type: ignore[reportGeneralTypeIssues] # noqa: E501 + table = to_table(summary, results) # type: ignore[reportGeneralTypeIssues] console.Console().print(table) @@ -180,7 +180,7 @@ def _ordered_failures( ) return sorted( counts, - key=lambda each: (each[1].unsuccessful_tests, each[0][0]), # type: ignore[reportUnknownLambdaType] # noqa: E501 + key=lambda each: (each[1].unsuccessful_tests, each[0][0]), # type: ignore[reportUnknownLambdaType] ) @@ -261,31 +261,31 @@ def _validation_results_table( def validator_for_dialect(dialect: str | None = None): - path = files("bowtie.schemas") / "io-schema.json" # type: ignore[reportUnknownMemberType] # noqa: E501 - root_schema = json.loads(path.read_text()) # type: ignore[reportUnknownArgumentType] # noqa: E501 + path = files("bowtie.schemas") / "io-schema.json" # type: ignore[reportUnknownMemberType] + root_schema = json.loads(path.read_text()) # type: ignore[reportUnknownArgumentType] from jsonschema.validators import ( validator_for, # type: ignore[reportUnknownVariableType] ) - Validator = validator_for(root_schema) # type: ignore[reportUnknownVariableType] # noqa: E501 - Validator.check_schema(root_schema) # type: ignore[reportUnknownMemberType] # noqa: E501 + Validator = validator_for(root_schema) # type: ignore[reportUnknownVariableType] + Validator.check_schema(root_schema) # type: ignore[reportUnknownMemberType] if dialect is None: - dialect = Validator.META_SCHEMA["$id"] # type: ignore[reportUnknownMemberType] # noqa: E501 + dialect = Validator.META_SCHEMA["$id"] # type: ignore[reportUnknownMemberType] - root_resource = referencing.Resource.from_contents(root_schema) # type: ignore[reportGeneralTypeIssues] # noqa: E501 - specification = referencing.jsonschema.specification_with(dialect) # type: ignore[reportGeneralTypeIssues] # noqa: E501 - registry = root_resource @ referencing.Registry().with_resource( # type: ignore[reportUnknownMemberType] # noqa: E501 + root_resource = referencing.Resource.from_contents(root_schema) # type: ignore[reportGeneralTypeIssues] + specification = referencing.jsonschema.specification_with(dialect) # type: ignore[reportGeneralTypeIssues] + registry = root_resource @ referencing.Registry().with_resource( # type: ignore[reportUnknownMemberType] uri=CURRENT_DIALECT_URI, resource=specification.create_resource({"$ref": dialect}), ) def validate(instance: Any, schema: Any) -> None: - validator = Validator(schema, registry=registry) # type: ignore[reportUnknownVariableType] # noqa: E501 - errors = list(validator.iter_errors(instance)) # type: ignore[reportUnknownMemberType] # noqa: E501 + validator = Validator(schema, registry=registry) # type: ignore[reportUnknownVariableType] + errors = list(validator.iter_errors(instance)) # type: ignore[reportUnknownMemberType] if errors: - raise _ProtocolError(errors=errors) # type: ignore[reportPrivateUsage] # noqa: E501 + raise _ProtocolError(errors=errors) # type: ignore[reportPrivateUsage] return validate @@ -298,7 +298,7 @@ def do_not_validate(dialect: str | None = None) -> Callable[..., None]: "--implementation", "-i", "image_names", - type=lambda name: name if "/" in name else f"{IMAGE_REPOSITORY}/{name}", # type: ignore[reportUnknownLambdaType] # noqa: E501 + type=lambda name: name if "/" in name else f"{IMAGE_REPOSITORY}/{name}", # type: ignore[reportUnknownLambdaType] help="A docker image which implements the bowtie IO protocol.", required=True, multiple=True, @@ -311,14 +311,14 @@ def do_not_validate(dialect: str | None = None) -> Callable[..., None]: "A URI or shortname identifying the dialect of each test case." f"Shortnames include: {sorted(DIALECT_SHORTNAMES)}." ), - type=lambda dialect: DIALECT_SHORTNAMES.get(dialect, dialect), # type: ignore[reportUnknownLambdaType] # noqa: E501 + type=lambda dialect: DIALECT_SHORTNAMES.get(dialect, dialect), # type: ignore[reportUnknownLambdaType] default=LATEST_DIALECT_NAME, show_default=True, ) FILTER = click.option( "-k", "filter", - type=lambda pattern: f"*{pattern}*", # type: ignore[reportUnknownLambdaType] # noqa: E501 + type=lambda pattern: f"*{pattern}*", # type: ignore[reportUnknownLambdaType] help="Only run cases whose description match the given glob pattern.", ) FAIL_FAST = click.option( @@ -361,7 +361,7 @@ def do_not_validate(dialect: str | None = None) -> Callable[..., None]: # I have no idea why Click makes this so hard, but no combination of: # type, default, is_flag, flag_value, nargs, ... # makes this work without doing it manually with callback. - callback=lambda _, __, v: validator_for_dialect if v else do_not_validate, # type: ignore[reportUnknownLambdaType] # noqa: E501 + callback=lambda _, __, v: validator_for_dialect if v else do_not_validate, # type: ignore[reportUnknownLambdaType] is_flag=True, help=( "When speaking to implementations (provided via -i), validate " @@ -504,7 +504,7 @@ async def _info(image_names: list[str], format: _F): # I have no idea why Click makes this so hard, but no combination of: # type, default, is_flag, flag_value, nargs, ... # makes this work without doing it manually with callback. - callback=lambda _, __, v: click.echo if not v else lambda *_, **__: None, # type: ignore[reportUnknownLambdaType] # noqa: E501 + callback=lambda _, __, v: click.echo if not v else lambda *_, **__: None, # type: ignore[reportUnknownLambdaType] is_flag=True, help="Don't print any output, just exit with nonzero status on failure.", ) @@ -587,10 +587,10 @@ async def _smoke( echo(json.dumps(serializable, indent=2)) case "pretty": async for case, response in responses: - if response.errored: # type: ignore[reportGeneralTypeIssues] # noqa: E501 + if response.errored: # type: ignore[reportGeneralTypeIssues] exit_code |= os.EX_DATAERR message = "❗ (error)" - elif response.failed: # type: ignore[reportGeneralTypeIssues] # noqa: E501 + elif response.failed: # type: ignore[reportGeneralTypeIssues] exit_code |= os.EX_DATAERR message = "✗ (failed)" else: @@ -631,19 +631,19 @@ def convert( from github3 import ( # type: ignore[reportMissingTypeStubs] GitHub, # type: ignore[reportUnknownVariableType] ) - from github3.exceptions import NotFoundError # type: ignore[reportMissingTypeStubs] # noqa: E501 + from github3.exceptions import NotFoundError # type: ignore[reportMissingTypeStubs] # isort: on - gh = GitHub(token=os.environ.get("GITHUB_TOKEN", "")) # type: ignore[reportUnknownVariableType] # noqa: E501 - repo = gh.repository("json-schema-org", "JSON-Schema-Test-Suite") # type: ignore[reportUnknownMemberType] # noqa: E501 + gh = GitHub(token=os.environ.get("GITHUB_TOKEN", "")) # type: ignore[reportUnknownVariableType] + repo = gh.repository("json-schema-org", "JSON-Schema-Test-Suite") # type: ignore[reportUnknownMemberType] _, _, rest = ( value[len(TEST_SUITE_URL) :].lstrip("/").partition("/") ) ref, sep, partial = rest.partition("/tests") data = BytesIO() - repo.archive(format="zipball", path=data, ref=ref) # type: ignore[reportUnknownMemberType] # noqa: E501 + repo.archive(format="zipball", path=data, ref=ref) # type: ignore[reportUnknownMemberType] data.seek(0) with zipfile.ZipFile(data) as zf: (contents,) = zipfile.Path(zf).iterdir() @@ -652,13 +652,13 @@ def convert( cases = list(cases) try: - commit = repo.commit(ref) # type: ignore[reportOptionalMemberAccess] # noqa: E501 + commit = repo.commit(ref) # type: ignore[reportOptionalMemberAccess] except NotFoundError: commit_info = ref else: # TODO: Make this the tree URL maybe, but I see tree(...) # doesn't come with an html_url - commit_info = {"text": commit.sha, "href": commit.html_url} # type: ignore[reportOptionalMemberAccess] # noqa: E501 + commit_info = {"text": commit.sha, "href": commit.html_url} # type: ignore[reportOptionalMemberAccess] run_metadata: dict[str, Any] = {"Commit": commit_info} if dialect is not None: @@ -814,11 +814,11 @@ async def _run( if fail_fast: # Stop after this case, since we still have futures out - should_stop = response.errored or response.failed # type: ignore[reportGeneralTypeIssues] # noqa: E501 + should_stop = response.errored or response.failed # type: ignore[reportGeneralTypeIssues] if should_stop: break - reporter.finished(count=seq, did_fail_fast=should_stop) # type: ignore[reportUnknownArgumentType] # noqa: E501 + reporter.finished(count=seq, did_fail_fast=should_stop) # type: ignore[reportUnknownArgumentType] if not seq: exit_code = os.EX_NOINPUT return exit_code @@ -844,7 +844,7 @@ async def _start(image_names: Iterable[str], **kwargs: Any): def sequenced( cases: Iterable[TestCase], reporter: _report.Reporter, -) -> Iterable[tuple[int, TestCase, _report._CaseReporter]]: # type: ignore[reportPrivateUsage] # noqa: E501 +) -> Iterable[tuple[int, TestCase, _report._CaseReporter]]: # type: ignore[reportPrivateUsage] for seq, case in enumerate(cases, 1): yield seq, case, reporter.case_started(seq=seq, case=case) @@ -951,10 +951,10 @@ def _rglob(path: _P, path_pattern: str) -> Iterable[_P]: def _relative_to(path: _P, other: Path) -> Path: if hasattr(path, "relative_to"): return path.relative_to(other) # type: ignore[reportGeneralTypeIssues] - return Path(path.at).relative_to(other.at) # type: ignore[reportUnknownArgumentType, reportUnknownMemberType] # noqa: E501 + return Path(path.at).relative_to(other.at) # type: ignore[reportUnknownArgumentType, reportUnknownMemberType] def _stem(path: _P) -> str: # Missing on < 3.11 if hasattr(path, "stem"): return path.stem - return Path(path.at).stem # type: ignore[reportUnknownArgumentType, reportUnknownMemberType] # noqa: E501 + return Path(path.at).stem # type: ignore[reportUnknownArgumentType, reportUnknownMemberType] diff --git a/bowtie/_commands.py b/bowtie/_commands.py index 3b7bb6429..390a09f26 100644 --- a/bowtie/_commands.py +++ b/bowtie/_commands.py @@ -125,7 +125,7 @@ def from_response( try: instance = json.loads(response) except json.JSONDecodeError as error: - raise exceptions._ProtocolError(errors=[error]) # type: ignore[reportPrivateUsage] # noqa: E501 + raise exceptions._ProtocolError(errors=[error]) # type: ignore[reportPrivateUsage] validate(instance=instance, schema=response_schema) return Response(**instance) @@ -237,7 +237,7 @@ class ReportableResult(Protocol): errored: bool failed: bool - def report(self, reporter: _report._CaseReporter) -> None: # type: ignore[reportPrivateUsage] # noqa: E501 + def report(self, reporter: _report._CaseReporter) -> None: # type: ignore[reportPrivateUsage] pass @@ -259,7 +259,7 @@ def from_dict(cls, data: Any, **kwargs: Any) -> CaseResult: def failed(self) -> bool: return any(failed for _, failed in self.compare()) - def report(self, reporter: _report._CaseReporter) -> None: # type: ignore[reportPrivateUsage] # noqa: E501 + def report(self, reporter: _report._CaseReporter) -> None: # type: ignore[reportPrivateUsage] reporter.got_results(self) def compare( @@ -270,7 +270,7 @@ def compare( not test.skipped and not test.errored and expected is not None - and expected != test.valid # type: ignore[reportUnknownMemberType] # noqa: E501 + and expected != test.valid # type: ignore[reportUnknownMemberType] ) yield test, failed @@ -290,7 +290,7 @@ class CaseErrored: caught: bool = True - def report(self, reporter: _report._CaseReporter): # type: ignore[reportPrivateUsage] # noqa: E501 + def report(self, reporter: _report._CaseReporter): # type: ignore[reportPrivateUsage] reporter.case_errored(self) @classmethod @@ -324,7 +324,7 @@ class CaseSkipped: issue_url: str | None = None skipped: bool = field(init=False, default=True) - def report(self, reporter: _report._CaseReporter): # type: ignore[reportPrivateUsage] # noqa: E501 + def report(self, reporter: _report._CaseReporter): # type: ignore[reportPrivateUsage] reporter.skipped(self) @@ -339,7 +339,7 @@ class Empty: implementation: str - def report(self, reporter: _report._CaseReporter): # type: ignore[reportPrivateUsage] # noqa: E501 + def report(self, reporter: _report._CaseReporter): # type: ignore[reportPrivateUsage] reporter.no_response(implementation=self.implementation) diff --git a/bowtie/_core.py b/bowtie/_core.py index 9ffec3a05..3cdfd16b4 100644 --- a/bowtie/_core.py +++ b/bowtie/_core.py @@ -85,15 +85,15 @@ async def receive(self) -> bytes: ) if message is not None: break - info: dict[str, Any] = await self._container.show() # type: ignore[reportUnknownMemberType] # noqa: E501 + info: dict[str, Any] = await self._container.show() # type: ignore[reportUnknownMemberType] if info["State"]["FinishedAt"]: raise StreamClosed(self) if message.stream == 2: # type: ignore[reportUnknownMemberType] data: list[bytes] = [] - while message.stream == 2: # type: ignore[reportUnknownMemberType] # noqa: E501 - data.append(message.data) # type: ignore[reportUnknownMemberType] # noqa: E501 + while message.stream == 2: # type: ignore[reportUnknownMemberType] + data.append(message.data) # type: ignore[reportUnknownMemberType] message = await self._read_with_timeout() if message is None: raise GotStderr(b"".join(data)) @@ -101,11 +101,11 @@ async def receive(self) -> bytes: line: bytes rest: list[bytes] while True: - line, *rest = message.data.split(b"\n") # type: ignore[reportUnknownMemberType] # noqa: E501 + line, *rest = message.data.split(b"\n") # type: ignore[reportUnknownMemberType] if rest: - line, self._last = self._last + line, rest.pop() # type: ignore[reportUnknownVariableType] # noqa: E501 + line, self._last = self._last + line, rest.pop() # type: ignore[reportUnknownVariableType] self._buffer.extend(rest) - return line # type: ignore[reportUnknownVariableType] # noqa: E501 + return line # type: ignore[reportUnknownVariableType] message = None while message is None: @@ -133,7 +133,7 @@ async def start( name=name, send=send, dialect=dialect, - start_response=await send(_commands.Dialect(dialect=dialect)), # type: ignore[reportGeneralTypeIssues] # noqa: E501 uh?? no idea what's going on here. + start_response=await send(_commands.Dialect(dialect=dialect)), # type: ignore[reportGeneralTypeIssues] # uh?? no idea what's going on here. ) def warn_if_unacknowledged(self, reporter: Reporter): @@ -152,7 +152,7 @@ async def run_case( command = _commands.Run(seq=seq, case=case.without_expected_results()) try: expected = [test.valid for test in case.tests] - response = await self._send(command) # type: ignore[reportGeneralTypeIssues] # noqa: E501 uh?? no idea what's going on here. + response = await self._send(command) # type: ignore[reportGeneralTypeIssues] # uh?? no idea what's going on here. if response is None: return _commands.Empty(implementation=self._name) return response(implementation=self._name, expected=expected) @@ -191,7 +191,7 @@ class Implementation: _stream: Stream = field(default=None, repr=False, alias="stream") _read_timeout_sec: float | None = field( default=2.0, - converter=lambda value: value or None, # type: ignore[reportUnknownArgumentType] # noqa: E501 + converter=lambda value: value or None, # type: ignore[reportUnknownArgumentType] repr=False, ) @@ -264,28 +264,28 @@ async def start( with suppress(GotStderr): # XXX: Log this too? await self._stop() with suppress(aiodocker.exceptions.DockerError): - await self._container.delete(force=True) # type: ignore[reportUnknownMemberType] # noqa: E501 + await self._container.delete(force=True) # type: ignore[reportUnknownMemberType] async def _start_container(self): - self._container = await self._docker.containers.run( # type: ignore[reportUnknownMemberType] # noqa: E501 + self._container = await self._docker.containers.run( # type: ignore[reportUnknownMemberType] config=dict( Image=self.name, OpenStdin=True, - HostConfig=dict(NetworkMode="none"), # type: ignore[reportUnknownArgumentType] # noqa: E501 + HostConfig=dict(NetworkMode="none"), # type: ignore[reportUnknownArgumentType] ), ) self._stream = Stream.attached_to( self._container, read_timeout_sec=self._read_timeout_sec, ) - started = await self._send(_commands.START_V1) # type: ignore[reportGeneralTypeIssues] # noqa: E501 uh?? no idea what's going on here. + started = await self._send(_commands.START_V1) # type: ignore[reportGeneralTypeIssues] # uh?? no idea what's going on here. if started is None: return self.metadata = started.implementation async def _restart_container(self): self._restarts -= 1 - await self._container.delete(force=True) # type: ignore[reportUnknownMemberType] # noqa: E501 + await self._container.delete(force=True) # type: ignore[reportUnknownMemberType] await self._start_container() await self.start_speaking(dialect=self._dialect) @@ -305,7 +305,7 @@ def start_speaking(self, dialect: str) -> Awaitable[DialectRunner]: ) async def _stop(self): - await self._send_no_response(_commands.STOP) # type: ignore[reportGeneralTypeIssues] # noqa: E501 uh?? no idea what's going on here. + await self._send_no_response(_commands.STOP) # type: ignore[reportGeneralTypeIssues] # uh?? no idea what's going on here. async def _send_no_response(self, cmd: _commands.Command[Any]): request = cmd.to_request(validate=self._maybe_validate) @@ -331,7 +331,7 @@ async def _send(self, cmd: _commands.Command[Any], retry: int = 3) -> Any: response=response, validate=self._maybe_validate, ) - except exceptions._ProtocolError as error: # type: ignore[reportPrivateUsage] # noqa: E501 + except exceptions._ProtocolError as error: # type: ignore[reportPrivateUsage] self._reporter.invalid_response( error=error, implementation=self, diff --git a/bowtie/_report.py b/bowtie/_report.py index 5aa41d43b..bdb52e318 100644 --- a/bowtie/_report.py +++ b/bowtie/_report.py @@ -193,9 +193,9 @@ def unsuccessful_tests(self): @mutable class _Summary: implementations: Iterable[dict[str, Any]] = field( - converter=lambda value: sorted( # type: ignore[reportUnknownArgumentType] # noqa: E501 + converter=lambda value: sorted( # type: ignore[reportUnknownArgumentType] value, # type: ignore[reportUnknownArgumentType] - key=lambda each: (each["language"], each["name"]), # type: ignore[reportUnknownArgumentType] # noqa: E501 + key=lambda each: (each["language"], each["name"]), # type: ignore[reportUnknownArgumentType] ), ) _combined: dict[int, Any] = field(factory=dict) @@ -274,10 +274,10 @@ def see_result(self, result: _commands.CaseResult): count.total_tests += 1 if test.skipped: count.skipped_tests += 1 - seen[result.implementation] = test.reason, "skipped" # type: ignore[reportGeneralTypeIssues] # noqa: E501 + seen[result.implementation] = test.reason, "skipped" # type: ignore[reportGeneralTypeIssues] elif test.errored: count.errored_tests += 1 - seen[result.implementation] = test.reason, "errored" # type: ignore[reportGeneralTypeIssues] # noqa: E501 + seen[result.implementation] = test.reason, "errored" # type: ignore[reportGeneralTypeIssues] else: if failed: count.failed_tests += 1