def test_make_rpc_parameter_schema_null(): def func(username=None): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) # Note that type is not set to null assert schema["properties"]["username"] == {"default": None}
def test_type(): def func(field: dict): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["field"] == {"type": "object"} assert schema["required"] == ["field"]
def test_optional(): def func(username: Optional[str]): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["username"] == {"anyOf": [{"type": "string"}, {"type": "null"}]} assert schema["required"] == ["username"]
def test_type_with_default(): def func(field: float = 3.142): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["field"] == {"type": "number", "default": 3.142} assert "required" not in schema
def test_named_tuple(): class User(NamedTuple): username: str password: str is_admin: bool = False def func(user: User): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["user"]["type"] == "object" assert schema["properties"]["user"]["properties"] == { "username": { "type": "string" }, "password": { "type": "string" }, "is_admin": { "type": "boolean", "default": False }, } assert set( schema["properties"]["user"]["required"]) == {"password", "username"}
def test_default(): def func(field=123): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["field"] == {"type": "number", "default": 123} assert "required" not in schema
def api_to_schema(api: "lightbus.Api") -> dict: """Produce a lightbus schema for the given API""" schema = {"rpcs": {}, "events": {}} if isinstance(api, type): raise InvalidApiForSchemaCreation( "An attempt was made to derive an API schema from a type/class, rather than " "from an instance of an API. This is probably because you are passing an API " "class to api_to_schema(), rather than an instance of the API class." ) for member_name, member in inspect.getmembers(api): if member_name.startswith("_"): # Don't create schema from private methods continue if hasattr(Api, member_name): # Don't create schema for methods defined on Api class continue if inspect.ismethod(member): schema["rpcs"][member_name] = { "parameters": make_rpc_parameter_schema(api.meta.name, member_name, method=member), "response": make_response_schema(api.meta.name, member_name, method=member), } elif isinstance(member, Event): schema["events"][member_name] = { "parameters": make_event_parameter_schema(api.meta.name, member_name, event=member) } return schema
def test_union(): def func(field: Union[str, int]): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["field"] == {"anyOf": [{"type": "string"}, {"type": "integer"}]} assert schema["required"] == ["field"]
def test_no_types(): def func(username): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["username"] == {} assert schema["required"] == ["username"] assert schema["additionalProperties"] is False
def test_positional_args(): def func(field: dict, *args): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert list(schema["properties"].keys()) == ["field"] # *args is ignored assert schema["required"] == ["field"] assert schema["additionalProperties"] is False
def test_named_tuple_with_none_default(): class User(NamedTuple): pass def func(user: User = None): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert len(schema["properties"]["user"]["anyOf"]) == 2
def test_kwargs(): def func(field: dict, **kwargs): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) # **kwargs isn't a property, but additionalProperties is now set to true assert list(schema["properties"].keys()) == ["field"] assert schema["required"] == ["field"] assert schema["additionalProperties"] is True
def test_make_rpc_parameter_schema_wrapped(): """Ensure wrapped functions are unwrapped""" def func(field: int): pass @functools.wraps(func) def wrapper(*args, **kwargs): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", wrapper) assert schema["properties"]["field"] == {"type": "integer"}
def test_named_tuple_field_with_none_default(): class Child(NamedTuple): pass class User(NamedTuple): foo: Child = None def func(user: User): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert len(schema["properties"]["user"]["properties"]["foo"]["oneOf"]) == 2
def test_named_tuple_optional_with_none_default(): # There is a risk of {'type': 'null'} being present twice here, # resulting in three values in anyOf. Check this doesn't happen class User(NamedTuple): pass def func(user: Optional[User] = None): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert len(schema["properties"]["user"]["anyOf"]) == 2
def test_union_default(): def func(field: Union[str, int] = 123): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["field"] == { "anyOf": [ {"type": "string", "default": 123}, # Technically an invalid default value {"type": "integer", "default": 123}, ] } assert "required" not in schema
def test_named_tuple_using_function(): User = namedtuple("User", ("username", "password")) def func(user: User): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["user"]["type"] == "object" assert schema["properties"]["user"]["properties"] == {"username": {}, "password": {}} assert set(schema["properties"]["user"]["required"]) == {"password", "username"}
def test_named_tuple_enum_with_default(): class MyEnum(Enum): foo: int = 1 bar: int = 2 class User(NamedTuple): field: MyEnum = MyEnum.bar def func(user: User): pass schema = make_rpc_parameter_schema("api_name", "rpc_name", func) assert schema["properties"]["user"]["type"] == "object" assert schema["properties"]["user"]["properties"] == { "field": {"type": "integer", "enum": [1, 2], "default": 2} } assert "required" not in schema["properties"]["user"]