Skip to content

Commit

Permalink
C++ refactoring: ak.with_name (#1233)
Browse files Browse the repository at this point in the history
* Worked on ak.with_name, two tests remaining to be fixed

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Renamed ak.with_name test to match the PR nr

* Fixed issue on mergemany for recordarray parameters

* Fixed all params passing in mergemany

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
ioanaif and pre-commit-ci[bot] authored Jan 20, 2022
1 parent 5738923 commit ab65e20
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/awkward/_v2/contents/indexedarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ def mergemany(self, others):
contentlength_so_far = 0
length_so_far = 0
nextindex = ak._v2.index.Index64.empty(total_length, self._nplike)
parameters = {}
parameters = self._parameters

for array in head:
parameters = ak._v2._util.merge_parameters(
Expand Down
2 changes: 1 addition & 1 deletion src/awkward/_v2/contents/indexedoptionarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ def mergemany(self, others):
contentlength_so_far = 0
length_so_far = 0
nextindex = ak._v2.index.Index64.empty(total_length, self._nplike)
parameters = {}
parameters = self._parameters

for array in head:
parameters = ak._v2._util.merge_parameters(
Expand Down
2 changes: 1 addition & 1 deletion src/awkward/_v2/contents/recordarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ def mergemany(self, others):

head, tail = self._merging_strategy(others)

parameters = {}
parameters = self._parameters
headless = head[1:]

for_each_field = []
Expand Down
2 changes: 1 addition & 1 deletion src/awkward/_v2/contents/unionarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ def mergemany(self, others):

nextcontents = []
length_so_far = 0
parameters = {}
parameters = self._parameters

for array in head:
parameters = ak._v2._util.merge_parameters(
Expand Down
102 changes: 50 additions & 52 deletions src/awkward/_v2/operations/structure/ak_with_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,53 @@


def with_name(array, name, highlevel=True, behavior=None):
raise NotImplementedError


# """
# Args:
# base: Data containing records or tuples.
# name (str): Name to give to the records or tuples; this assigns
# the `"__record__"` parameter.
# highlevel (bool): 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.

# Returns an #ak.Array or #ak.Record (or low-level equivalent, if
# `highlevel=False`) with a new name. This function does not change the
# array in-place.

# The records or tuples may be nested within multiple levels of nested lists.
# If records are nested within records, only the outermost are affected.

# Setting the `"__record__"` parameter makes it possible to add behaviors
# to the data; see #ak.Array and #ak.behavior for a more complete
# description.
# """

# def getfunction(layout):
# if isinstance(layout, ak._v2.contents.RecordArray):
# parameters = dict(layout.parameters)
# parameters["__record__"] = name
# return lambda: ak._v2.contents.RecordArray(
# layout.contents,
# layout.recordlookup,
# len(layout),
# layout.identities,
# parameters,
# )
# else:
# return None

# out = ak._v2._util.recursively_apply(
# ak._v2.operations.convert.to_layout(array), getfunction, pass_depth=False
# )

# def getfunction2(layout):
# if isinstance(layout, ak._v2._util.uniontypes):
# return lambda: layout.simplify(merge=True, mergebool=False)
# else:
# return None

# out2 = ak._v2._util.recursively_apply(out, getfunction2, pass_depth=False)

# return ak._v2._util.maybe_wrap_like(out2, array, behavior, highlevel)

"""
Args:
base: Data containing records or tuples.
name (str): Name to give to the records or tuples; this assigns
the `"__record__"` parameter.
highlevel (bool): 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.
Returns an #ak.Array or #ak.Record (or low-level equivalent, if
`highlevel=False`) with a new name. This function does not change the
array in-place.
The records or tuples may be nested within multiple levels of nested lists.
If records are nested within records, only the outermost are affected.
Setting the `"__record__"` parameter makes it possible to add behaviors
to the data; see #ak.Array and #ak.behavior for a more complete
description.
"""

layout = ak._v2.operations.convert.to_layout(array)

def action(layout, **ignore):
if isinstance(layout, ak._v2.contents.RecordArray):
parameters = dict(layout.parameters)
parameters["__record__"] = name
return ak._v2.contents.RecordArray(
layout.contents,
layout.fields,
len(layout),
layout.identifier,
parameters,
)
else:
return None

out = layout.recursively_apply(action)

def action2(layout, **ignore):
if layout.is_UnionType:
return layout.simplify_uniontype(merge=True, mergebool=False)
else:
return None

out2 = out.recursively_apply(action2)

return ak._v2._util.wrap(out2, behavior, highlevel)
34 changes: 34 additions & 0 deletions tests/v2/test_0049-distinguish-record-and-recordarray-behaviors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE

from __future__ import absolute_import

import pytest # noqa: F401
import numpy as np # noqa: F401
import awkward as ak # noqa: F401


class Point(ak._v2.record.Record):
def __repr__(self):
return "<{} {}>".format(self["x"], self["y"])


@pytest.mark.skip(reason="Missing check for overridden __repr__")
def test():
behavior = {}
behavior["__typestr__", "Point"] = "P"
behavior["Point"] = Point
array = ak._v2.highlevel.Array(
[
[{"x": 1, "y": [1.1]}, {"x": 2, "y": [2.0, 0.2]}],
[],
[{"x": 3, "y": [3.0, 0.3, 3.3]}],
],
with_name="Point",
behavior=behavior,
check_valid=True,
)
assert repr(array[0, 0]) == "<1 [1.1]>"
assert repr(array[0]) == "<Array [<1 [1.1]>, <2 [2, 0.2]>] type='2 * P'>"
assert (
repr(array) == "<Array [[<1 [1.1]>, ... <3 [3, 0.3, 3.3]>]] type='3 * var * P'>"
)
29 changes: 29 additions & 0 deletions tests/v2/test_0788-indexedarray-carrying-recordarray-parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE

from __future__ import absolute_import

import pytest # noqa: F401
import numpy as np # noqa: F401
import awkward as ak # noqa: F401


def test():
one = ak._v2.highlevel.Array([[{"x": 1}], [], [{"x": 2}]], with_name="One")
two = ak._v2.highlevel.Array([[{"x": 1.1}], [], [{"x": 2.2}]], with_name="Two")
assert (
str(
ak._v2.operations.structure.with_name(
ak._v2.operations.structure.concatenate([one, two], axis=1), "All"
).type
)
== "3 * var * All[x: float64]"
)
assert (
str(
ak._v2.operations.structure.with_name(
ak._v2.operations.structure.concatenate([one[1:], two[1:]], axis=1),
"All",
).type
)
== "2 * var * All[x: float64]"
)
79 changes: 79 additions & 0 deletions tests/v2/test_1233-ak-with_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE

from __future__ import absolute_import

import pytest # noqa: F401
import numpy as np # noqa: F401
import awkward as ak # noqa: F401

to_list = ak._v2.operations.convert.to_list


def test_with_name():
array = ak._v2.highlevel.Array(
[
{"x": 0.0, "y": []},
{"x": 1.1, "y": [1]},
{"x": 2.2, "y": [2, 2]},
{"x": 3.3, "y": [3, 3, 3]},
]
)

one = ak._v2.operations.structure.with_name(array, "Wilbur")
assert isinstance(one.layout, ak._v2.contents.Content)
assert one.layout.parameters["__record__"] == "Wilbur"

array2 = ak._v2.operations.convert.from_iter(
[
[[1], 2.2, [2, 2], 3.3, [3, 3, 3], 4.4, [4, 4, 4, 4]],
[
{"x": 0.0, "y": []},
{"x": 1.1, "y": [1]},
{"x": 2.2, "y": [2, 2]},
{"x": 3.3, "y": [3, 3, 3]},
],
],
highlevel=False,
)
one = ak._v2.operations.structure.with_name(array2, "Wilbur")
assert one.layout.content.contents[2].parameters["__record__"] == "Wilbur"

array = ak._v2.highlevel.Array(
[
{"a": [[0.0, 4.5], [], None], "b": []},
{"a": 1.1, "b": [[1]]},
]
)
one = ak._v2.operations.structure.with_name(array, "James")
assert isinstance(one.layout, ak._v2.contents.Content)
assert one.layout.parameters["__record__"] == "James"


def test_simplify_unionarray_with_name():
one = ak._v2.operations.convert.from_iter([5, 4, 3, 2, 1], highlevel=False)
two = ak._v2.operations.convert.from_iter(
[[], [1], [2, 2], [3, 3, 3]], highlevel=False
)
three = ak._v2.operations.convert.from_iter(
[
{"x": 0.0, "y": []},
{"x": 1.1, "y": [1]},
{"x": 2.2, "y": [2, 2]},
{"x": 3.3, "y": [3, 3, 3]},
],
highlevel=False,
)

tags2 = ak._v2.index.Index8(np.array([0, 1, 0, 1, 0, 0, 1], dtype=np.int8))
index2 = ak._v2.index.Index32(np.array([0, 0, 1, 1, 2, 3, 2], dtype=np.int32))
inner = ak._v2.contents.UnionArray(tags2, index2, [two, three])
tags1 = ak._v2.index.Index8(
np.array([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0], dtype=np.int8)
)
index1 = ak._v2.index.Index64(
np.array([0, 1, 0, 1, 2, 2, 3, 4, 5, 3, 6, 4], dtype=np.int64)
)
outer = ak._v2.contents.UnionArray(tags1, index1, [one, inner])
one = ak._v2.operations.structure.with_name(outer, "James")

assert outer.contents[1].is_UnionType != one.layout.contents[1].is_UnionType

0 comments on commit ab65e20

Please sign in to comment.