Skip to content

Commit

Permalink
Review responses
Browse files Browse the repository at this point in the history
  • Loading branch information
devinrsmith committed Jun 14, 2024
1 parent 3cf7e9f commit 7e81e41
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<!--<logger name="io.netty" level="INFO"/>-->
<!--<logger name="io.deephaven" level="INFO"/>-->

<root level="info">
<root level="warn">
<appender-ref ref="LOGBUFFER" />
</root>
</configuration>
105 changes: 55 additions & 50 deletions py/server/deephaven/json/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"big_decimal_val",
"array_val",
"object_val",
"typed_object_val",
"object_entries_val",
"tuple_val",
"any_val",
Expand All @@ -45,7 +46,7 @@
"JsonValue",
"JsonValueType",
"RepeatedFieldBehavior",
"FieldOptions",
"ObjectField",
]

_JValue = jpy.get_type("io.deephaven.json.Value")
Expand Down Expand Up @@ -106,10 +107,37 @@ def j_object(self) -> jpy.JType:
JsonValue,
dtypes.DType,
type,
Dict[str, Union["JsonValueType", "FieldOptions"]],
Dict[str, Union["JsonValueType", "ObjectField"]],
List["JsonValueType"],
Tuple["JsonValueType", ...],
]
"""The JSON value alias"""


def json_val(json_value_type: JsonValueType) -> JsonValue:
"""Creates a JsonValue from a JsonValueType.
Args:
json_value_type (JsonValueType): the JSON value type
Returns:
the JSON value
"""
if isinstance(json_value_type, JsonValue):
return json_value_type
if isinstance(json_value_type, dtypes.DType):
return _dtype_dict[json_value_type]
if isinstance(json_value_type, type):
return _type_dict[json_value_type]
if isinstance(json_value_type, Dict):
return object_val(json_value_type)
if isinstance(json_value_type, List):
if len(json_value_type) is not 1:
raise TypeError("Expected List as json type to have exactly one element")
return array_val(json_value_type[0])
if isinstance(json_value_type, Tuple):
return tuple_val(json_value_type)
raise TypeError(f"Unsupported JSON value type {type(json_value_type)}")


class RepeatedFieldBehavior(Enum):
Expand All @@ -130,16 +158,16 @@ class RepeatedFieldBehavior(Enum):


@dataclass
class FieldOptions:
class ObjectField:
"""The object field options.
In contexts where the user needs to create an object field value and isn't changing any default values, the user can
simplify by just using the JsonValueType. For example,
.. code-block:: python
{
"name": FieldOptions(str),
"age": FieldOptions(int),
"name": ObjectField(str),
"age": ObjectField(int),
}
could be simplified to
Expand All @@ -151,7 +179,7 @@ class FieldOptions:
}
"""

value: JsonValueType
value_type: JsonValueType
"""The json value type"""
aliases: Union[str, List[str]] = field(default_factory=list)
"""The field name aliases. By default, is an empty list."""
Expand All @@ -164,7 +192,7 @@ def _j_field_options(self, name: str) -> jpy.JType:
builder = (
_JObjectField.builder()
.name(name)
.options(json_val(self.value).j_value)
.options(json_val(self.value_type).j_value)
.repeatedBehavior(self.repeated_behavior.value)
.caseSensitive(self.case_sensitive)
)
Expand Down Expand Up @@ -199,7 +227,7 @@ def _build(


def object_val(
fields: Dict[str, Union[JsonValueType, FieldOptions]],
fields: Dict[str, Union[JsonValueType, ObjectField]],
allow_unknown_fields: bool = True,
allow_missing: bool = True,
allow_null: bool = True,
Expand All @@ -217,7 +245,7 @@ def object_val(
object_val({ "name": str, "age": int })
In contexts where the user needs to create a JsonValueType and isn't changing any default values, the user can
simplify by using a Dict[str, Union[JsonValueType, FieldOptions]]. For example,
simplify by using a Dict[str, Union[JsonValueType, ObjectField]]. For example,
.. code-block:: python
some_method(object_val({ "name": str, "age": int }))
Expand All @@ -228,14 +256,14 @@ def object_val(
some_method({ "name": str, "age": int })
Args:
fields (Dict[str, Union[JsonValueType, FieldOptions]]): the fields
fields (Dict[str, Union[JsonValueType, ObjectField]]): the fields
allow_unknown_fields (bool): if unknown fields are allow, by default is True
allow_missing (bool): if the object is allowed to be missing, by default is True
allow_null (bool): if the object is allowed to be a JSON null type, by default is True
repeated_field_behavior (RepeatedFieldBehavior): the default repeated field behavior, only used for fields that
are specified using JsonValueType, by default is RepeatedFieldBehavior.ERROR
case_sensitive (bool): if default to use for field case-sensitivity. Only used for fields that are specified
using JsonValueType, by default is True
case_sensitive (bool): if the field name and aliases should be compared using case-sensitive equality, only used
for fields that are specified using JsonValueType, by default is True
Returns:
the object value
Expand All @@ -246,8 +274,8 @@ def object_val(
for field_name, field_opts in fields.items():
field_opts = (
field_opts
if isinstance(field_opts, FieldOptions)
else FieldOptions(
if isinstance(field_opts, ObjectField)
else ObjectField(
field_opts,
repeated_behavior=repeated_field_behavior,
case_sensitive=case_sensitive,
Expand All @@ -260,7 +288,7 @@ def object_val(

def typed_object_val(
type_field: str,
shared_fields: Dict[str, Union[JsonValueType, FieldOptions]],
shared_fields: Dict[str, Union[JsonValueType, ObjectField]],
objects: Dict[str, JsonValueType],
allow_unknown_types: bool = True,
allow_missing: bool = True,
Expand Down Expand Up @@ -298,8 +326,8 @@ def typed_object_val(
Args:
type_field (str): the type-discriminating field
shared_fields (Dict[str, Union[JsonValueType, FieldOptions]]): the shared fields
objects (Dict[str, Union[JsonValueType, FieldOptions]]): the individual objects, keyed by their
shared_fields (Dict[str, Union[JsonValueType, ObjectField]]): the shared fields
objects (Dict[str, Union[JsonValueType, ObjectField]]): the individual objects, keyed by their
type-discriminated value. The values must be object options.
allow_unknown_types (bool): if unknown types are allow, by default is True
allow_missing (bool): if the object is allowed to be missing, by default is True
Expand All @@ -323,8 +351,8 @@ def typed_object_val(
for shared_field_name, shared_field_opts in shared_fields.items():
shared_field_opts = (
shared_field_opts
if isinstance(shared_field_opts, FieldOptions)
else FieldOptions(
if isinstance(shared_field_opts, ObjectField)
else ObjectField(
shared_field_opts,
repeated_behavior=RepeatedFieldBehavior.ERROR,
case_sensitive=True,
Expand Down Expand Up @@ -380,8 +408,8 @@ def array_val(


def object_entries_val(
value_type: JsonValueType,
key_type: JsonValueType = str,
value_type: Optional[JsonValueType] = None,
allow_missing: bool = True,
allow_null: bool = True,
) -> JsonValue:
Expand All @@ -400,11 +428,11 @@ def object_entries_val(
might be modelled as the object kv type
.. code-block:: python
object_entries_val(value_type=int)
object_entries_val(int)
Args:
key_type (JsonValueType): the key element, by defaults is type str
value_type (Optional[JsonValueType]): the value element, required
value_type (JsonValueType): the value type element, required
key_type (JsonValueType): the key type element, by default is type str
allow_missing (bool): if the object is allowed to be missing, by default is True
allow_null (bool): if the object is allowed to be a JSON null type, by default is True
Expand Down Expand Up @@ -438,6 +466,8 @@ def tuple_val(
.. code-block:: python
tuple_val({"name": str, "age": int, "height": float})
otherwise, default names based on the indexes of the values will be used.
In contexts where the user needs to create a JsonValueType and isn't changing any default values nor is setting
names, the user can simplify passing through a python tuple type. For example,
Expand Down Expand Up @@ -957,7 +987,8 @@ def instant_val(
allow_missing (bool): if the Instant value is allowed to be missing, default is True
allow_null (bool): if the Instant value is allowed to be a JSON null type, default is True
number_format (Literal[None, "s", "ms", "us", "ns"]): when set, signifies that a JSON numeric type is expected.
"s" is for seconds, "ms" is for milliseconds, "us" is for microseconds, and "ns" is for nanoseconds.
"s" is for seconds, "ms" is for milliseconds, "us" is for microseconds, and "ns" is for nanoseconds since
the epoch. When not set, a JSON string in the ISO-8601 format is expected.
allow_decimal (bool): if the Instant value is allowed to be a JSON decimal type, default is False. Only valid
when number_format is specified.
on_missing (Optional[Any]): the value to use when the JSON value is missing and allow_missing is True, default is None.
Expand Down Expand Up @@ -1159,32 +1190,6 @@ def _allow(x: Optional[bool]) -> bool:
return JsonValue(builder.build())


def json_val(json_value_type: JsonValueType) -> JsonValue:
"""Creates a JsonValue from a JsonValueType.
Args:
json_value_type (JsonValueType): the JSON value type
Returns:
the JSON value
"""
if isinstance(json_value_type, JsonValue):
return json_value_type
if isinstance(json_value_type, dtypes.DType):
return _dtype_dict[json_value_type]
if isinstance(json_value_type, type):
return _type_dict[json_value_type]
if isinstance(json_value_type, Dict):
return object_val(json_value_type)
if isinstance(json_value_type, List):
if len(json_value_type) is not 1:
raise TypeError("Expected List as json type to have exactly one element")
return array_val(json_value_type[0])
if isinstance(json_value_type, Tuple):
return tuple_val(json_value_type)
raise TypeError(f"Unsupported JSON value type {type(json_value_type)}")


_dtype_dict = {
dtypes.bool_: bool_val(),
dtypes.char: char_val(),
Expand Down
15 changes: 8 additions & 7 deletions py/server/deephaven/json/jackson.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
#

"""A JSON processor provider implementation using Jackson."""
"""A JSON processor provider implementation using Jackson (https://github.com/FasterXML/jackson)."""

import jpy

Expand All @@ -12,20 +12,21 @@


def provider(
json_value: JsonValueType, factory: Optional[jpy.JType] = None
json_value_type: JsonValueType, factory: Optional[jpy.JType] = None
) -> jpy.JType:
"""Creates a jackson JSON named object processor provider.
"""Creates a Jackson JSON named object processor provider.
Args:
json_value(JsonValueType): the JSON value
factory(Optional[jpy.JType]): the factory (java type "com.fasterxml.jackson.core.JsonFactory"), by default is None
json_value_type (JsonValueType): the JSON value
factory (Optional[jpy.JType]): the factory (java type "com.fasterxml.jackson.core.JsonFactory"), by default is
None which will use a default factory
Returns:
the jackson JSON named object processor provider
"""
_JProvider = jpy.get_type("io.deephaven.json.jackson.JacksonProvider")
return (
_JProvider.of(json_val(json_value).j_value, factory)
_JProvider.of(json_val(json_value_type).j_value, factory)
if factory
else _JProvider.of(json_val(json_value).j_value)
else _JProvider.of(json_val(json_value_type).j_value)
)
14 changes: 6 additions & 8 deletions py/server/tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def all_same_json(self, items):
self.all_same_json_internal(
[array_val(x) for x in items] + [[x] for x in items]
)
self.all_same_json_internal([object_entries_val(value_type=x) for x in items])
self.all_same_json_internal([object_entries_val(x) for x in items])
self.all_same_json_internal([object_val({"Foo": x}) for x in items])
self.all_same_json_internal(
[tuple_val((x,)) for x in items] + [(x,) for x in items]
Expand All @@ -34,9 +34,7 @@ def all_same_json(self, items):
self.all_same_json_internal(
[array_val(array_val(x)) for x in items] + [[[x]] for x in items]
)
self.all_same_json_internal(
[object_entries_val(value_type=array_val(x)) for x in items]
)
self.all_same_json_internal([object_entries_val(array_val(x)) for x in items])

def test_bool(self):
self.all_same_json([bool_val(), dtypes.bool_, bool])
Expand Down Expand Up @@ -129,8 +127,8 @@ def test_object(self):
e1 = [
{"name": str, "age": int},
{"name": string_val(), "age": long_val()},
{"name": FieldOptions(str), "age": FieldOptions(int)},
{"name": FieldOptions(string_val()), "age": FieldOptions(long_val())},
{"name": ObjectField(str), "age": ObjectField(int)},
{"name": ObjectField(string_val()), "age": ObjectField(long_val())},
]
e2 = [object_val(x) for x in e1]
self.all_same_json(e1 + e2)
Expand Down Expand Up @@ -161,8 +159,8 @@ def test_tuple(self):
def test_object_entries(self):
self.all_same_json(
[
object_entries_val(value_type=int),
object_entries_val(value_type=long_val()),
object_entries_val(int),
object_entries_val(long_val()),
]
)

Expand Down

0 comments on commit 7e81e41

Please sign in to comment.