From 1998a514218c4267818b74dc8a5be80747995428 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Thu, 29 Sep 2022 13:57:55 +0100 Subject: [PATCH] Enable autoformatters / linters for most implementations. Closes: #32. --- .pre-commit-config.yaml | 45 ++++++++++- bowtie/_cli.py | 43 ++++++----- bowtie/_commands.py | 7 +- bowtie/_core.py | 3 +- bowtie/_report.py | 6 +- .../lua-jsonschema/bowtie_jsonschema.lua | 22 +++--- implementations/lua-jsonschema/stylua.toml | 5 ++ .../bowtie-fastjsonschema | 1 - implementations/python-jschon/bowtie-jschon | 1 - .../python-jsonschema/bowtie-jsonschema | 7 +- .../ruby-json_schemer/.rubocop.yml | 11 +++ implementations/ruby-json_schemer/Gemfile | 3 +- .../bowtie_json_schemer.gemspec | 11 +-- .../ruby-json_schemer/bowtie_json_schemer.rb | 77 ++++++++++--------- implementations/rust-jsonschema/src/main.rs | 13 +++- noxfile.py | 31 ++++++-- .../envsonschema/envsonschema | 5 +- tests/test_integration.py | 12 ++- 18 files changed, 201 insertions(+), 102 deletions(-) create mode 100644 implementations/lua-jsonschema/stylua.toml create mode 100644 implementations/ruby-json_schemer/.rubocop.yml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a3937ca40..d7661b8f1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,50 @@ repos: rev: 5.10.1 hooks: - id: isort + - repo: https://github.com/asottile/yesqa + rev: v1.4.0 + hooks: + - id: yesqa + - repo: https://github.com/asottile/pyupgrade + rev: v2.38.2 + hooks: + - id: pyupgrade + - repo: https://github.com/psf/black + rev: 22.8.0 + hooks: + - name: black (python implementations & bowtie internals) + id: black + args: ["--line-length", "79"] - repo: https://github.com/pre-commit/mirrors-prettier rev: "v3.0.0-alpha.0" hooks: - - id: prettier + - name: prettier (javascript implementations & bowtie internals) + id: prettier + - repo: https://github.com/doublify/pre-commit-rust + rev: "v1.0" + hooks: + - name: cargo fmt (rust implementations) + id: fmt + args: + [ + "--manifest-path", + "implementations/rust-jsonschema/Cargo.toml", + "--", + ] + - repo: https://github.com/syntaqx/git-hooks + rev: v0.0.17 + hooks: + - name: go fmt (golang implementations) + id: go-fmt + - repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: "3.0.0" + hooks: + - name: rubocop (ruby implementations) + id: rubocop + - repo: https://github.com/JohnnyMorganz/StyLua + rev: v0.15.1 + hooks: + - name: stylua (lua implementations) + id: stylua + exclude: .*/json.lua + args: ["--config-path", "implementations/lua-jsonschema/stylua.toml"] diff --git a/bowtie/_cli.py b/bowtie/_cli.py index 3080e1fa0..c607a5349 100644 --- a/bowtie/_cli.py +++ b/bowtie/_cli.py @@ -33,22 +33,17 @@ "2020-12": DRAFT2020, "draft2020-12": DRAFT2020, "draft202012": DRAFT2020, - "2019": DRAFT2019, "201909": DRAFT2019, "2019-09": DRAFT2019, "draft2019-09": DRAFT2019, "draft201909": DRAFT2019, - "7": DRAFT7, "draft7": DRAFT7, - "6": DRAFT6, "draft6": DRAFT6, - "4": DRAFT4, "draft4": DRAFT4, - "3": DRAFT3, "draft3": DRAFT3, } @@ -71,7 +66,9 @@ def main(): type=click.File(mode="r"), ) @click.option( - "--out", "-o", "output", + "--out", + "-o", + "output", help="Where to write the outputted report HTML.", default="bowtie-report.html", type=click.File("w"), @@ -114,23 +111,28 @@ def do_not_validate(dialect: str | None = None): IMPLEMENTATION = click.option( - "--implementation", "-i", "image_names", + "--implementation", + "-i", + "image_names", help="A docker image which implements the bowtie IO protocol.", multiple=True, ) FILTER = click.option( - "-k", "filter", + "-k", + "filter", type=lambda pattern: f"*{pattern}*", help="Only run cases whose description match the given glob pattern.", ) FAIL_FAST = click.option( - "-x", "--fail-fast", + "-x", + "--fail-fast", is_flag=True, default=False, help="Fail immediately after the first error or disagreement.", ) SET_SCHEMA = click.option( - "--set-schema/--no-set-schema", "-S", + "--set-schema/--no-set-schema", + "-S", "set_schema", default=False, help=( @@ -140,7 +142,9 @@ def do_not_validate(dialect: str | None = None): ), ) VALIDATE = click.option( - "--validate-implementations", "-V", "make_validator", + "--validate-implementations", + "-V", + "make_validator", # 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. @@ -164,7 +168,9 @@ def do_not_validate(dialect: str | None = None): @SET_SCHEMA @VALIDATE @click.option( - "--dialect", "-D", "dialect", + "--dialect", + "-D", + "dialect", help=( "A URI or shortname identifying the dialect of each test case." f"Shortnames include: {sorted(DIALECT_SHORTNAMES)}." @@ -185,8 +191,7 @@ def run(context, input, filter, **kwargs): cases = (TestCase.from_dict(**json.loads(line)) for line in input) if filter: cases = ( - case for case in cases - if fnmatch(case["description"], filter) + case for case in cases if fnmatch(case["description"], filter) ) count = asyncio.run(_run(**kwargs, cases=cases)) @@ -230,8 +235,7 @@ def suite(context, input, filter, **kwargs): if filter: cases = ( - case for case in cases - if fnmatch(case["description"], filter) + case for case in cases if fnmatch(case["description"], filter) ) count = asyncio.run(_run(**kwargs, dialect=dialect, cases=cases)) @@ -258,7 +262,8 @@ async def _run( image_name=image_name, make_validator=make_validator, ), - ) for image_name in image_names + ) + for image_name in image_names ] reporter.will_speak(dialect=dialect) acknowledged, runners = [], [] @@ -337,6 +342,7 @@ def stderr_processor(logger, method_name, event_dict): ), ) return event_dict + return stderr_processor @@ -351,7 +357,8 @@ def redirect_structlog(file=sys.stderr): structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.processors.TimeStamper( - fmt="%Y-%m-%d %H:%M.%S", utc=False, + fmt="%Y-%m-%d %H:%M.%S", + utc=False, ), _stderr_processor(file), structlog.dev.ConsoleRenderer( diff --git a/bowtie/_commands.py b/bowtie/_commands.py index d76f13eb9..e93c13b7f 100644 --- a/bowtie/_commands.py +++ b/bowtie/_commands.py @@ -40,10 +40,8 @@ def without_expected_results(self): as_dict.update( attrs.asdict( self, - filter=lambda k, v: k.name != "tests" and ( - k.name not in {"comment", "registry"} - or v is not None - ), + filter=lambda k, v: k.name != "tests" + and (k.name not in {"comment", "registry"} or v is not None), ), ) return as_dict @@ -81,6 +79,7 @@ def from_response(self, response, validate): cls.to_request = to_request cls.from_response = from_response return attrs.define(cls) + return _command diff --git a/bowtie/_core.py b/bowtie/_core.py index 0d765315d..2894c0035 100644 --- a/bowtie/_core.py +++ b/bowtie/_core.py @@ -125,7 +125,8 @@ class Implementation: _docker: aiodocker.Docker = attrs.field(repr=False) _restarts: int = attrs.field(default=20 + 1, repr=False) _container: aiodocker.containers.DockerContainer = attrs.field( - default=None, repr=False, + default=None, + repr=False, ) _stream: Stream = attrs.field(default=None, repr=False) diff --git a/bowtie/_report.py b/bowtie/_report.py index 2293312df..43cceb561 100644 --- a/bowtie/_report.py +++ b/bowtie/_report.py @@ -41,8 +41,10 @@ def unacknowledged_dialect(self, implementation, dialect, response): def ready(self, implementations, dialect): metadata = { implementation.name: dict( - implementation.metadata, image=implementation.name, - ) for implementation in implementations + implementation.metadata, + image=implementation.name, + ) + for implementation in implementations } self._write(implementations=metadata) diff --git a/implementations/lua-jsonschema/bowtie_jsonschema.lua b/implementations/lua-jsonschema/bowtie_jsonschema.lua index a4c70bdfa..a923bf3fc 100755 --- a/implementations/lua-jsonschema/bowtie_jsonschema.lua +++ b/implementations/lua-jsonschema/bowtie_jsonschema.lua @@ -7,7 +7,7 @@ io.stdout:setvbuf 'no' local cmds = { start = function(request) - assert(request.version == 1, "Wrong version!") + assert(request.version == 1, 'Wrong version!') STARTED = true return { ready = true, @@ -23,23 +23,21 @@ local cmds = { 'http://json-schema.org/draft-06/schema#', 'http://json-schema.org/draft-04/schema#', }, - } + }, } end, dialect = function(_) - assert(STARTED, "Not started!") + assert(STARTED, 'Not started!') return { ok = false } end, run = function(request) - assert(STARTED, "Not started!") + assert(STARTED, 'Not started!') - local validate = jsonschema.generate_validator( - request.case.schema, { - external_resolver = function(url) - return request.case.registry[url] - end, - } - ) + local validate = jsonschema.generate_validator(request.case.schema, { + external_resolver = function(url) + return request.case.registry[url] + end, + }) local results = {} for _, test in ipairs(request.case.tests) do table.insert(results, { valid = validate(test.instance) }) @@ -47,7 +45,7 @@ local cmds = { return { seq = request.seq, results = results } end, stop = function(_) - assert(STARTED, "Not started!") + assert(STARTED, 'Not started!') os.exit(0) end, } diff --git a/implementations/lua-jsonschema/stylua.toml b/implementations/lua-jsonschema/stylua.toml new file mode 100644 index 000000000..1e464e429 --- /dev/null +++ b/implementations/lua-jsonschema/stylua.toml @@ -0,0 +1,5 @@ +column_width = 120 +indent_type = "Spaces" +indent_width = 2 +quote_style = "AutoPreferSingle" +call_parentheses = "NoSingleString" diff --git a/implementations/python-fastjsonschema/bowtie-fastjsonschema b/implementations/python-fastjsonschema/bowtie-fastjsonschema index 807159615..3697a906c 100755 --- a/implementations/python-fastjsonschema/bowtie-fastjsonschema +++ b/implementations/python-fastjsonschema/bowtie-fastjsonschema @@ -37,7 +37,6 @@ class Runner: issues=( "https://github.com/horejsek/python-fastjsonschema/issues" ), - dialects=[ "http://json-schema.org/draft-07/schema#", "http://json-schema.org/draft-06/schema#", diff --git a/implementations/python-jschon/bowtie-jschon b/implementations/python-jschon/bowtie-jschon index 574012b1e..050277ef9 100755 --- a/implementations/python-jschon/bowtie-jschon +++ b/implementations/python-jschon/bowtie-jschon @@ -62,7 +62,6 @@ class Runner: version=metadata.version("jschon"), homepage="https://jschon.readthedocs.io/", issues="https://github.com/marksparkza/jschon/issues", - dialects=[ "https://json-schema.org/draft/2020-12/schema", "https://json-schema.org/draft/2019-09/schema", diff --git a/implementations/python-jsonschema/bowtie-jsonschema b/implementations/python-jsonschema/bowtie-jsonschema index c84a140b5..2cfd6bbe4 100755 --- a/implementations/python-jsonschema/bowtie-jsonschema +++ b/implementations/python-jsonschema/bowtie-jsonschema @@ -39,7 +39,6 @@ class Runner: issues=( "https://github.com/python-jsonschema/jsonschema/issues" ), - dialects=[ "https://json-schema.org/draft/2020-12/schema", "https://json-schema.org/draft/2019-09/schema", @@ -61,9 +60,9 @@ class Runner: schema = case["schema"] try: Validator = validator_for(schema, self._DefaultValidator) - assert Validator is not None, ( - "No dialect sent and schema is missing $schema." - ) + assert ( + Validator is not None + ), "No dialect sent and schema is missing $schema." registry = case.get("registry", {}) resolver = RefResolver.from_schema(schema, store=registry) diff --git a/implementations/ruby-json_schemer/.rubocop.yml b/implementations/ruby-json_schemer/.rubocop.yml new file mode 100644 index 000000000..ef225eb9d --- /dev/null +++ b/implementations/ruby-json_schemer/.rubocop.yml @@ -0,0 +1,11 @@ +AllCops: + TargetRubyVersion: 3.0 + +Style/TrailingCommaInArguments: + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInArrayLiteral: + EnforcedStyleForMultiline: comma diff --git a/implementations/ruby-json_schemer/Gemfile b/implementations/ruby-json_schemer/Gemfile index 0770e99e8..5f10ba8c9 100644 --- a/implementations/ruby-json_schemer/Gemfile +++ b/implementations/ruby-json_schemer/Gemfile @@ -1,3 +1,4 @@ # frozen_string_literal: true -source "https://rubygems.org" + +source 'https://rubygems.org' gemspec diff --git a/implementations/ruby-json_schemer/bowtie_json_schemer.gemspec b/implementations/ruby-json_schemer/bowtie_json_schemer.gemspec index 6662b6c40..0594a4d63 100644 --- a/implementations/ruby-json_schemer/bowtie_json_schemer.gemspec +++ b/implementations/ruby-json_schemer/bowtie_json_schemer.gemspec @@ -1,10 +1,11 @@ # frozen_string_literal: true Gem::Specification.new do |spec| - spec.name = "bowtie_json_schemer" - spec.version = "0.1.0" - spec.summary = "Bowtie + json_schemer" - spec.authors = ["Bowtie Authors"] + spec.name = 'bowtie_json_schemer' + spec.version = '0.1.0' + spec.summary = 'Bowtie + json_schemer' + spec.authors = ['Bowtie Authors'] + spec.required_ruby_version = '>= 3.0' - spec.add_dependency "json_schemer", "~> 0.2" + spec.add_dependency 'json_schemer', '~> 0.2' end diff --git a/implementations/ruby-json_schemer/bowtie_json_schemer.rb b/implementations/ruby-json_schemer/bowtie_json_schemer.rb index 88eb7e3f5..d19487db9 100644 --- a/implementations/ruby-json_schemer/bowtie_json_schemer.rb +++ b/implementations/ruby-json_schemer/bowtie_json_schemer.rb @@ -11,56 +11,59 @@ class WrongVersion < StandardError class NotStarted < StandardError end +# Bowtie implementation for json_schemer module BowtieJsonSchemer + @started = false + @draft = nil - @@started = false - @@draft = nil - - ARGF.each_line do |line| + ARGF.each_line do |line| # rubocop:disable Metrics/BlockLength request = JSON.parse(line) - case request["cmd"] - when "start" - raise WrongVersion if request["version"] != 1 - @@started = true + case request['cmd'] + when 'start' + raise WrongVersion if request['version'] != 1 + + @started = true response = { - :ready => true, - :version => 1, - :implementation => { - :language => :ruby, - :name => :json_schemer, - :homepage => "https://github.com/davishmcclurg/json_schemer", - :issues => "https://github.com/davishmcclurg/json_schemer/issues", + ready: true, + version: 1, + implementation: { + language: :ruby, + name: :json_schemer, + homepage: 'https://github.com/davishmcclurg/json_schemer', + issues: 'https://github.com/davishmcclurg/json_schemer/issues', - :dialects => [ - "http://json-schema.org/draft-07/schema#", - "http://json-schema.org/draft-06/schema#", - "http://json-schema.org/draft-04/schema#", - ], - } + dialects: [ + 'http://json-schema.org/draft-07/schema#', + 'http://json-schema.org/draft-06/schema#', + 'http://json-schema.org/draft-04/schema#', + ], + }, } puts "#{JSON.generate(response)}\n" - when "dialect" - raise NotStarted if not @@started - @@draft = JSONSchemer::DRAFT_CLASS_BY_META_SCHEMA[request["dialect"]] - response = { :ok => true } + when 'dialect' + raise NotStarted unless @started + + @draft = JSONSchemer::DRAFT_CLASS_BY_META_SCHEMA[request['dialect']] + response = { ok: true } puts "#{JSON.generate(response)}\n" - when "run" - raise NotStarted if not @@started - schemer = @@draft.new( - request["case"]["schema"], - ref_resolver: proc { |uri| request["case"]["registry"][uri.to_s] }, + when 'run' + raise NotStarted unless @started + + schemer = @draft.new( + request['case']['schema'], + ref_resolver: proc { |uri| request['case']['registry'][uri.to_s] }, ) response = { - :seq => request["seq"], - :results => request["case"]["tests"].map{ |test| - {:valid => schemer.valid?(test["instance"]) } - }, + seq: request['seq'], + results: request['case']['tests'].map do |test| + { valid: schemer.valid?(test['instance']) } + end, } puts "#{JSON.generate(response)}\n" - when "stop" - raise NotStarted if not @@started + when 'stop' + raise NotStarted unless @started + exit(0) end end - end diff --git a/implementations/rust-jsonschema/src/main.rs b/implementations/rust-jsonschema/src/main.rs index b6a77cf90..fc34e5696 100644 --- a/implementations/rust-jsonschema/src/main.rs +++ b/implementations/rust-jsonschema/src/main.rs @@ -4,18 +4,21 @@ use jsonschema::{Draft, JSONSchema, SchemaResolver, SchemaResolverError}; use serde_json::{json, Result}; use url::Url; - struct InMemoryResolver { registry: serde_json::Value, } impl SchemaResolver for InMemoryResolver { - fn resolve(&self, _root_schema: &serde_json::Value, url: &Url, _original_reference: &str) -> core::result::Result, SchemaResolverError> { + fn resolve( + &self, + _root_schema: &serde_json::Value, + url: &Url, + _original_reference: &str, + ) -> core::result::Result, SchemaResolverError> { return Ok(Arc::new(self.registry[url.to_string()].to_owned())); } } - fn main() -> Result<()> { let dialects = HashMap::from([ ( @@ -89,7 +92,9 @@ fn main() -> Result<()> { let case = &request["case"]; let registry = &case["registry"]; - let resolver = InMemoryResolver { registry: registry.to_owned() }; + let resolver = InMemoryResolver { + registry: registry.to_owned(), + }; compiler = compiler.with_resolver(resolver); let compiled = compiler.compile(&case["schema"]).expect("Invalid schema!"); diff --git a/noxfile.py b/noxfile.py index 92e61fd14..73b67daab 100644 --- a/noxfile.py +++ b/noxfile.py @@ -30,11 +30,15 @@ def shiv(session): tmpdir = Path(session.create_tmp()) out = tmpdir / "bowtie" session.run( - "python", "-m", "shiv", + "python", + "-m", + "shiv", "--reproducible", - "-c", "bowtie", + "-c", + "bowtie", str(ROOT), - "-o", str(out), + "-o", + str(out), ) print(f"Outputted a shiv to {out}.") @@ -62,9 +66,14 @@ def style(session): @nox.session(tags=["docs"]) @nox.parametrize( - "builder", [ - nox.param(name, id=name) for name in [ - "dirhtml", "doctest", "linkcheck", "spelling", + "builder", + [ + nox.param(name, id=name) + for name in [ + "dirhtml", + "doctest", + "linkcheck", + "spelling", ] ], ) @@ -75,8 +84,14 @@ def docs(session, builder): if builder != "spelling": argv += ["-q"] session.run( - "python", "-m", "sphinx", "-b", builder, - str(DOCS), str(tmpdir / builder), *argv, + "python", + "-m", + "sphinx", + "-b", + builder, + str(DOCS), + str(tmpdir / builder), + *argv, ) diff --git a/tests/fauxmplementations/envsonschema/envsonschema b/tests/fauxmplementations/envsonschema/envsonschema index c2ff987ef..6525342fd 100755 --- a/tests/fauxmplementations/envsonschema/envsonschema +++ b/tests/fauxmplementations/envsonschema/envsonschema @@ -91,6 +91,7 @@ class Runner: ) return self.send(**result) elif instruction == "split": + def send(**response): dumped = json.dumps(response) size = len(dumped) // 2 @@ -116,7 +117,9 @@ class Runner: if instruction == "valid": result = _VALID.get(arg, {"valid": arg}) elif instruction == "skip": - result = dict(each.split("=", 1) for each in arg.split(",")) + result = dict( + each.split("=", 1) for each in arg.split(",") + ) result.update(skipped=True) elif instruction == "error": result = dict( diff --git a/tests/test_integration.py b/tests/test_integration.py index 639d378e9..c4fc67296 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -36,6 +36,7 @@ async def _image(docker): ) yield tag await docker.images.delete(name=tag, force=True) + return _image @@ -46,7 +47,11 @@ async def _image(docker): @asynccontextmanager async def bowtie(*args): proc = await asyncio.create_subprocess_exec( - sys.executable, "-m", "bowtie", "run", *args, + sys.executable, + "-m", + "bowtie", + "run", + *args, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, @@ -72,6 +77,7 @@ async def _send(stdin=""): else: errors.append(each) return proc.returncode, successful, errors, stderr + yield _send @@ -91,7 +97,9 @@ async def test_validating_on_both_sides(lintsonschema): @pytest.mark.asyncio async def test_it_runs_tests_from_a_file(tmp_path, envsonschema): tests = tmp_path / "tests.jsonl" - tests.write_text("""{"description": "foo", "schema": {}, "tests": [{"description": "bar", "instance": {}}] }\n""") # noqa: E501 + tests.write_text( + """{"description": "foo", "schema": {}, "tests": [{"description": "bar", "instance": {}}] }\n""", # noqa: E501 + ) async with bowtie("-i", envsonschema, tests) as send: returncode, results, _, stderr = await send()