diff --git a/src/awkward/_v2/operations/convert/ak_from_iter.py b/src/awkward/_v2/operations/convert/ak_from_iter.py index 31dd8bd658..6581bf2189 100644 --- a/src/awkward/_v2/operations/convert/ak_from_iter.py +++ b/src/awkward/_v2/operations/convert/ak_from_iter.py @@ -90,5 +90,5 @@ def _impl(iterable, highlevel, behavior, allow_record, initial, resize): form = ak._v2.forms.from_json(formstr) return ak._v2.operations.convert.from_buffers( - form, length, buffers, highlevel=highlevel + form, length, buffers, highlevel=highlevel, behavior=behavior ) diff --git a/src/awkward/_v2/operations/convert/ak_from_json_schema.py b/src/awkward/_v2/operations/convert/ak_from_json_schema.py index 84724a7120..811d8fc9ed 100644 --- a/src/awkward/_v2/operations/convert/ak_from_json_schema.py +++ b/src/awkward/_v2/operations/convert/ak_from_json_schema.py @@ -160,7 +160,9 @@ def _impl( else: length = 1 - out = ak._v2.operations.convert.from_buffers(form, length, container) + out = ak._v2.operations.convert.from_buffers( + form, length, container, highlevel=highlevel, behavior=behavior + ) if schema.get("type") == "array": return out diff --git a/src/awkward/_v2/operations/structure/ak_argcartesian.py b/src/awkward/_v2/operations/structure/ak_argcartesian.py index a96d089d19..208c2d1e79 100644 --- a/src/awkward/_v2/operations/structure/ak_argcartesian.py +++ b/src/awkward/_v2/operations/structure/ak_argcartesian.py @@ -112,7 +112,12 @@ def _impl(arrays, axis, nested, parameters, with_name, highlevel, behavior): parameters["__record__"] = with_name result = ak._v2.operations.structure.cartesian( - layouts, axis=axis, nested=nested, parameters=parameters, highlevel=False + layouts, + axis=axis, + nested=nested, + parameters=parameters, + highlevel=False, + behavior=behavior, ) return ak._v2._util.wrap(result, behavior, highlevel) diff --git a/src/awkward/_v2/operations/structure/ak_broadcast_arrays.py b/src/awkward/_v2/operations/structure/ak_broadcast_arrays.py index 6291564604..3469610139 100644 --- a/src/awkward/_v2/operations/structure/ak_broadcast_arrays.py +++ b/src/awkward/_v2/operations/structure/ak_broadcast_arrays.py @@ -16,6 +16,8 @@ def broadcast_arrays(*arrays, **kwargs): right-broadcasting, as described below. highlevel (bool, default is True): If True, return an #ak.Array; otherwise, return a low-level #ak.layout.Content subclass. + behavior (None or dict): Custom #ak.behavior for the output array, if + high-level. depth_limit (None or int, default is None): If None, attempt to fully broadcast the `arrays` to all levels. If an int, limit the number of dimensions that get broadcasted. The minimum value is `1`, @@ -138,11 +140,18 @@ def broadcast_arrays(*arrays, **kwargs): def _impl(arrays, kwargs): - (highlevel, depth_limit, left_broadcast, right_broadcast) = ak._v2._util.extra( + ( + highlevel, + behavior, + depth_limit, + left_broadcast, + right_broadcast, + ) = ak._v2._util.extra( (), kwargs, [ ("highlevel", True), + ("behavior", None), ("depth_limit", None), ("left_broadcast", True), ("right_broadcast", True), @@ -165,7 +174,7 @@ def action(inputs, depth, **kwargs): else: return None - behavior = ak._v2._util.behavior_of(*arrays) + behavior = ak._v2._util.behavior_of(*arrays, behavior=behavior) out = ak._v2._broadcasting.broadcast_and_apply( inputs, action, diff --git a/src/awkward/_v2/operations/structure/ak_cartesian.py b/src/awkward/_v2/operations/structure/ak_cartesian.py index 1ec14f0587..37346d4607 100644 --- a/src/awkward/_v2/operations/structure/ak_cartesian.py +++ b/src/awkward/_v2/operations/structure/ak_cartesian.py @@ -446,7 +446,7 @@ def getfunction3(inputs, depth, **kwargs): while len(toflatten) != 0: flatten_axis = toflatten.pop() result = ak._v2.operations.structure.flatten( - result, axis=flatten_axis, highlevel=False + result, axis=flatten_axis, highlevel=False, behavior=behavior ) return ak._v2._util.wrap(result, behavior, highlevel) diff --git a/src/awkward/_v2/operations/structure/ak_strings_astype.py b/src/awkward/_v2/operations/structure/ak_strings_astype.py index fe38e6f5f2..3cf4f39551 100644 --- a/src/awkward/_v2/operations/structure/ak_strings_astype.py +++ b/src/awkward/_v2/operations/structure/ak_strings_astype.py @@ -54,10 +54,10 @@ def action(layout, **kwargs): or layout.parameter("__array__") == "bytestring" ): layout = ak._v2.operations.structure.without_parameters( - layout, highlevel=False + layout, highlevel=False, behavior=behavior ) max_length = ak._v2.operations.reducers.max( - ak._v2.operations.structure.num(layout) + ak._v2.operations.structure.num(layout, behavior=behavior) ) regulararray = layout.rpad(max_length, 1) maskedarray = ak._v2.operations.convert.to_numpy( diff --git a/src/awkward/_v2/operations/structure/ak_unzip.py b/src/awkward/_v2/operations/structure/ak_unzip.py index 29dc64808b..996dd5be62 100644 --- a/src/awkward/_v2/operations/structure/ak_unzip.py +++ b/src/awkward/_v2/operations/structure/ak_unzip.py @@ -51,7 +51,7 @@ def check_for_union(layout, **kwargs): elif isinstance(layout, ak._v2.contents.UnionArray): for content in layout.contents: - if set(ak.operations.describe.fields(content)) != set(fields): + if set(ak._v2.operations.describe.fields(content)) != set(fields): raise ak._v2._util.error( ValueError("union of different sets of fields, cannot ak.unzip") ) diff --git a/src/awkward/_v2/operations/structure/ak_where.py b/src/awkward/_v2/operations/structure/ak_where.py index 40be5a8b10..15a80c6311 100644 --- a/src/awkward/_v2/operations/structure/ak_where.py +++ b/src/awkward/_v2/operations/structure/ak_where.py @@ -21,6 +21,8 @@ def where(condition, *args, **kwargs): buffers with distinct types (using an #ak.layout.UnionArray8_64). highlevel (bool, default is True): If True, return an #ak.Array; otherwise, return a low-level #ak.layout.Content subclass. + behavior (None or dict): Custom #ak.behavior for the output array, if + high-level. This function has a one-argument form, `condition` without `x` or `y`, and a three-argument form, `condition`, `x`, and `y`. In the one-argument form, @@ -36,8 +38,8 @@ def where(condition, *args, **kwargs): for all `i`. The structure of `x` and `y` do not need to be the same; if they are incompatible types, the output will have #ak.type.UnionType. """ - mergebool, highlevel = ak._v2._util.extra( - (), kwargs, [("mergebool", True), ("highlevel", True)] + mergebool, highlevel, behavior = ak._v2._util.extra( + (), kwargs, [("mergebool", True), ("highlevel", True), ("behavior", None)] ) if len(args) == 0: @@ -45,7 +47,7 @@ def where(condition, *args, **kwargs): "ak._v2.where", dict(condition=condition, mergebool=mergebool, highlevel=highlevel), ): - return _impl1(condition, mergebool, highlevel) + return _impl1(condition, mergebool, highlevel, behavior) elif len(args) == 1: raise ak._v2._util.error( @@ -60,7 +62,7 @@ def where(condition, *args, **kwargs): condition=condition, x=x, y=y, mergebool=mergebool, highlevel=highlevel ), ): - return _impl3(condition, x, y, mergebool, highlevel) + return _impl3(condition, x, y, mergebool, highlevel, behavior) else: raise ak._v2._util.error( @@ -71,7 +73,7 @@ def where(condition, *args, **kwargs): ) -def _impl1(condition, mergebool, highlevel): +def _impl1(condition, mergebool, highlevel, behavior): akcondition = ak._v2.operations.convert.to_layout( condition, allow_record=False, allow_other=False ) @@ -84,7 +86,8 @@ def _impl1(condition, mergebool, highlevel): if highlevel: return tuple( ak._v2._util.wrap( - ak._v2.contents.NumpyArray(x), ak._v2._util.behavior_of(condition) + ak._v2.contents.NumpyArray(x), + ak._v2._util.behavior_of(condition, behavior=behavior), ) for x in out ) @@ -92,7 +95,7 @@ def _impl1(condition, mergebool, highlevel): return tuple(ak._v2.contents.NumpyArray(x) for x in out) -def _impl3(condition, x, y, mergebool, highlevel): +def _impl3(condition, x, y, mergebool, highlevel, behavior): akcondition = ak._v2.operations.convert.to_layout( condition, allow_record=False, allow_other=False ) @@ -122,7 +125,7 @@ def action(inputs, **kwargs): else: return None - behavior = ak._v2._util.behavior_of(condition, x, y) + behavior = ak._v2._util.behavior_of(condition, x, y, behavior=behavior) out = ak._v2._broadcasting.broadcast_and_apply( [akcondition, left, right], action, diff --git a/src/awkward/_v2/operations/structure/ak_with_parameter.py b/src/awkward/_v2/operations/structure/ak_with_parameter.py index 12fd6e6de8..b5a34f469b 100644 --- a/src/awkward/_v2/operations/structure/ak_with_parameter.py +++ b/src/awkward/_v2/operations/structure/ak_with_parameter.py @@ -39,6 +39,7 @@ def with_parameter(array, parameter, value, highlevel=True, behavior=None): def _impl(array, parameter, value, highlevel, behavior): + behavior = ak._v2._util.behavior_of(array, behavior=behavior) layout = ak._v2.operations.convert.to_layout( array, allow_record=True, allow_other=False ) diff --git a/src/awkward/_v2/operations/structure/ak_without_parameters.py b/src/awkward/_v2/operations/structure/ak_without_parameters.py index e9d6e2e5b2..c47736a7fe 100644 --- a/src/awkward/_v2/operations/structure/ak_without_parameters.py +++ b/src/awkward/_v2/operations/structure/ak_without_parameters.py @@ -28,6 +28,7 @@ def without_parameters(array, highlevel=True, behavior=None): def _impl(array, highlevel, behavior): + behavior = ak._v2._util.behavior_of(array, behavior=behavior) layout = ak._v2.operations.convert.to_layout( array, allow_record=True, allow_other=False ) diff --git a/tests/v2/test_1415-behaviour-forwarding.py b/tests/v2/test_1415-behaviour-forwarding.py new file mode 100644 index 0000000000..11c7083aea --- /dev/null +++ b/tests/v2/test_1415-behaviour-forwarding.py @@ -0,0 +1,145 @@ +# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE + +import pytest # noqa: F401 +import awkward as ak # noqa: F401 +import numpy as np + +one = ak._v2.Array([[0.0, 1.1, 2.2, None], [], [3.3, 4.4]]) +two = ak._v2.Array([[100, 200, 300, 400], [300], [400, 500]]) + + +def test_behavior_forwarding_structure(): + three = ak._v2.operations.convert.from_iter( + [[0.99999], [6], [2.99999]], highlevel=True + ) + four = ak._v2.operations.convert.from_iter( + [[1.00001], [6], [3.00001]], highlevel=True + ) + mask1 = ak._v2.highlevel.Array([[True, True, False, False], [True], [True, False]]) + five = ak._v2.Array(["1.1", "2.2", " 3.3 ", "00004.4", "-5.5"]) + + six = ak._v2.Array( + [{"x": 1}, {"x": 2}, {"x": 3}, {"x": 3}, {"x": 3}], check_valid=True + ) + seven = ak._v2.Array([1.1, 2.2, 3.3, 4.4, 5.5], check_valid=True) + + assert ( + ak._v2.operations.structure.argcartesian([one, two], behavior={})[0].behavior + == {} + ) + assert ( + ak._v2.operations.structure.argcombinations(one, 2, behavior={})[0].behavior + == {} + ) + assert ak._v2.operations.structure.argsort(one, behavior={})[0].behavior == {} + + assert ( + ak._v2.operations.structure.broadcast_arrays( + 5, ak._v2.Array([[0.0, 1.1, 2.2], [], [3.3, 4.4]], behavior={}) + )[0].behavior + == {} + ) + + assert ak._v2.operations.structure.cartesian([one], behavior={})[0].behavior == {} + assert ( + ak._v2.operations.structure.combinations(one, 2, behavior={})[0].behavior == {} + ) + assert ( + ak._v2.operations.structure.concatenate([one, two], behavior={})[0].behavior + == {} + ) + + assert ak._v2.operations.structure.fill_none(one, 42, behavior={})[0].behavior == {} + assert ak._v2.operations.structure.flatten(one, behavior={}).behavior == {} + assert ak._v2.operations.structure.from_regular(one, behavior={})[0].behavior == {} + assert ak._v2.operations.structure.full_like(one, 6, behavior={})[0].behavior == {} + + assert ak._v2.operations.structure.is_none(one, behavior={}).behavior == {} + assert ak._v2.operations.structure.isclose(three, four, behavior={}).behavior == {} + + assert ak._v2.operations.structure.local_index(one, behavior={})[0].behavior == {} + + assert ak._v2.operations.structure.mask(two, mask1, behavior={})[0].behavior == {} + + assert ak._v2.operations.structure.nan_to_num(one, behavior={})[0].behavior == {} + assert ak._v2.operations.structure.num(one, behavior={}).behavior == {} + + assert ak._v2.operations.structure.ones_like(one, behavior={})[0].behavior == {} + + assert ak._v2.operations.structure.packed(one, behavior={})[0].behavior == {} + assert ak._v2.operations.structure.pad_none(one, 6, behavior={})[0].behavior == {} + + assert ak._v2.operations.structure.ravel(one, behavior={}).behavior == {} + assert ak._v2.operations.structure.run_lengths(one, behavior={})[0].behavior == {} + + assert ak._v2.operations.structure.sort(one, behavior={})[0].behavior == {} + assert ( + ak._v2.operations.structure.strings_astype( + five, np.float64, behavior={} + ).behavior + == {} + ) + + assert ak._v2.operations.structure.to_regular(three, behavior={})[0].behavior == {} + + assert ak._v2.operations.structure.unflatten(five, 2, behavior={})[0].behavior == {} + assert ( + ak._v2.operations.structure.unzip(ak._v2.Array([{"x": 1}], behavior={}))[ + 0 + ].behavior + == {} + ) + + assert ( + ak._v2.operations.structure.values_astype(one, "float32", behavior={})[ + 0 + ].behavior + == {} + ) + + assert ( + ak._v2.operations.structure.where( + ak._v2.highlevel.Array( + [[True, True], [True, False], [True, False]], behavior={} + ) + )[0].behavior + == {} + ) + assert ( + ak._v2.operations.structure.with_field(six, seven, where="y", behavior={})[ + 0 + ].behavior + == {} + ) + assert ( + ak._v2.operations.structure.with_name(six, "cloud", behavior={})[0].behavior + == {} + ) + assert ( + ak._v2.operations.structure.without_parameters( + ak._v2.operations.structure.with_parameter( + one, "__array__", "cloud", behavior={} + ) + )[0].behavior + == {} + ) + + assert ak._v2.operations.structure.zeros_like(one, behavior={})[0].behavior == {} + assert ak._v2.operations.structure.zip([five, seven], behavior={})[0].behavior == {} + + +def test_behavior_forwarding_convert(): + assert ( + ak._v2.operations.convert.from_json_schema( + " [ 1 ,2 ,3.0, 4, 5] \n ", + {"type": "array", "items": {"type": "integer"}}, + behavior={}, + ).behavior + == {} + ) + + +@pytest.mark.skip(reason="FIXME: v2 highlevel implemented yet") +def test_behaviour_notimplemented(): + assert ak._v2.operations.structure.firsts([one, two], behavior={})[0].behavior == {} + assert ak._v2.operations.structure.singletons(one, behavior={})[0].behavior == {}