Skip to content

Commit

Permalink
Kill an if statement by pushing it into click.
Browse files Browse the repository at this point in the history
  • Loading branch information
Julian committed Sep 29, 2022
1 parent f02c528 commit ff30600
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 34 deletions.
41 changes: 34 additions & 7 deletions bowtie/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from contextlib import AsyncExitStack
from fnmatch import fnmatch
from importlib import resources
from pathlib import Path
from urllib.parse import urljoin
import asyncio
Expand Down Expand Up @@ -89,6 +90,29 @@ def report(input, output):
output.write(template.render(**_report.from_input(input)))


def validator_for_dialect(dialect: str | None = None):
from jsonschema.validators import RefResolver, validator_for

text = resources.read_text("bowtie.schemas", "io-schema.json")
root_schema = json.loads(text)
resolver = RefResolver.from_schema(root_schema)
Validator = validator_for(root_schema)
Validator.check_schema(root_schema)

if dialect is None:
dialect = Validator.META_SCHEMA["$id"]

def validate(instance, schema):
resolver.store["urn:current-dialect"] = {"$ref": dialect}
Validator(schema, resolver=resolver).validate(instance)

return validate


def do_not_validate(dialect: str | None = None):
return lambda *args, **kwargs: None


IMPLEMENTATION = click.option(
"--implementation", "-i", "image_names",
help="A docker image which implements the bowtie IO protocol.",
Expand Down Expand Up @@ -116,13 +140,16 @@ def report(input, output):
),
)
VALIDATE = click.option(
"--validate-implementations/--no-validate-implementations", "-V",
"validate_implementations",
default=False,
"--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.
callback=lambda _, __, v: validator_for_dialect if v else do_not_validate,
is_flag=True,
help=(
"When speaking to implementations (provided via -i), validate "
"(or don't validate) the requests and responses sent to them. "
"Generally, this option protects against broken Bowtie "
"the requests and responses sent to them under Bowtie's JSON Schema "
"specification. Generally, this option protects against broken Bowtie "
"implementations and can be left at its default (of off) unless "
"you are developing a new implementation container."
),
Expand Down Expand Up @@ -218,7 +245,7 @@ async def _run(
dialect: str,
fail_fast: bool,
set_schema: bool,
validate_implementations: bool,
make_validator: callable,
reporter: _report.Reporter = _report.Reporter(),
):
async with AsyncExitStack() as stack:
Expand All @@ -229,7 +256,7 @@ async def _run(
Implementation.start(
docker=docker,
image_name=image_name,
validate_implementations=validate_implementations,
make_validator=make_validator,
),
) for image_name in image_names
]
Expand Down
28 changes: 1 addition & 27 deletions bowtie/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from collections import deque
from contextlib import asynccontextmanager
from importlib import resources
import asyncio
import json

Expand Down Expand Up @@ -136,13 +135,7 @@ class Implementation:

@classmethod
@asynccontextmanager
async def start(cls, docker, image_name, validate_implementations):
if validate_implementations:
make_validator = validator_for_dialect
else:
def make_validator(dialect=None):
return lambda instance, schema: None

async def start(cls, docker, image_name, make_validator):
self = cls(
name=image_name,
docker=docker,
Expand Down Expand Up @@ -210,22 +203,3 @@ async def _send(self, cmd, retry=3):
)
except asyncio.exceptions.TimeoutError:
continue


def validator_for_dialect(dialect: str | None = None):
from jsonschema.validators import RefResolver, validator_for

text = resources.read_text("bowtie.schemas", "io-schema.json")
root_schema = json.loads(text)
resolver = RefResolver.from_schema(root_schema)
Validator = validator_for(root_schema)
Validator.check_schema(root_schema)

if dialect is None:
dialect = Validator.META_SCHEMA["$id"]

def validate(instance, schema):
resolver.store["urn:current-dialect"] = {"$ref": dialect}
Validator(schema, resolver=resolver).validate(instance)

return validate

0 comments on commit ff30600

Please sign in to comment.