This is an automated email from the ASF dual-hosted git repository.
wesm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new d1db0b0 ARROW-9374: [C++][Python] Expose MakeArrayFromScalar
d1db0b0 is described below
commit d1db0b08da7fad1fd171c7275264b87a3d9435dc
Author: Krisztián Szűcs <[email protected]>
AuthorDate: Mon Jul 13 12:25:33 2020 -0500
ARROW-9374: [C++][Python] Expose MakeArrayFromScalar
Since we have a complete scalar implementation on the python side, we can
implement `pa.repeat(value, size=n)`
Closes #7684 from kszucs/repeat
Authored-by: Krisztián Szűcs <[email protected]>
Signed-off-by: Wes McKinney <[email protected]>
---
cpp/src/arrow/array/array_test.cc | 86 +++++++++++++++++++------
cpp/src/arrow/array/util.cc | 70 ++++++++++++++++----
cpp/src/arrow/scalar.cc | 2 +-
cpp/src/arrow/scalar.h | 6 +-
cpp/src/arrow/scalar_test.cc | 12 ++++
python/pyarrow/__init__.py | 4 +-
python/pyarrow/array.pxi | 120 +++++++++++++++++++++++++++++++++++
python/pyarrow/includes/libarrow.pxd | 3 +
python/pyarrow/scalar.pxi | 14 ++--
python/pyarrow/tests/test_array.py | 56 ++++++++++++++++
python/pyarrow/tests/test_scalars.py | 11 ++++
11 files changed, 339 insertions(+), 45 deletions(-)
diff --git a/cpp/src/arrow/array/array_test.cc
b/cpp/src/arrow/array/array_test.cc
index ea1ded6..42e25d0 100644
--- a/cpp/src/arrow/array/array_test.cc
+++ b/cpp/src/arrow/array/array_test.cc
@@ -354,25 +354,39 @@ TEST_F(TestArray, TestMakeArrayFromScalar) {
ASSERT_EQ(null_array->null_count(), 5);
auto hello = Buffer::FromString("hello");
- ScalarVector scalars{std::make_shared<BooleanScalar>(false),
- std::make_shared<Int8Scalar>(3),
- std::make_shared<UInt16Scalar>(3),
- std::make_shared<Int32Scalar>(3),
- std::make_shared<UInt64Scalar>(3),
- std::make_shared<DoubleScalar>(3.0),
- std::make_shared<BinaryScalar>(hello),
- std::make_shared<LargeBinaryScalar>(hello),
- std::make_shared<FixedSizeBinaryScalar>(
- hello,
fixed_size_binary(static_cast<int32_t>(hello->size()))),
- std::make_shared<Decimal128Scalar>(Decimal128(10),
decimal(16, 4)),
- std::make_shared<StringScalar>(hello),
- std::make_shared<LargeStringScalar>(hello),
- std::make_shared<StructScalar>(
- ScalarVector{
- std::make_shared<Int32Scalar>(2),
- std::make_shared<Int32Scalar>(6),
- },
- struct_({field("min", int32()), field("max",
int32())}))};
+ DayTimeIntervalType::DayMilliseconds daytime{1, 100};
+
+ ScalarVector scalars{
+ std::make_shared<BooleanScalar>(false),
+ std::make_shared<Int8Scalar>(3),
+ std::make_shared<UInt16Scalar>(3),
+ std::make_shared<Int32Scalar>(3),
+ std::make_shared<UInt64Scalar>(3),
+ std::make_shared<DoubleScalar>(3.0),
+ std::make_shared<Date32Scalar>(10),
+ std::make_shared<Date64Scalar>(11),
+ std::make_shared<Time32Scalar>(1000, time32(TimeUnit::SECOND)),
+ std::make_shared<Time64Scalar>(1111, time64(TimeUnit::MICRO)),
+ std::make_shared<TimestampScalar>(1111, timestamp(TimeUnit::MILLI)),
+ std::make_shared<MonthIntervalScalar>(1),
+ std::make_shared<DayTimeIntervalScalar>(daytime),
+ std::make_shared<DurationScalar>(60, duration(TimeUnit::SECOND)),
+ std::make_shared<BinaryScalar>(hello),
+ std::make_shared<LargeBinaryScalar>(hello),
+ std::make_shared<FixedSizeBinaryScalar>(
+ hello, fixed_size_binary(static_cast<int32_t>(hello->size()))),
+ std::make_shared<Decimal128Scalar>(Decimal128(10), decimal(16, 4)),
+ std::make_shared<StringScalar>(hello),
+ std::make_shared<LargeStringScalar>(hello),
+ std::make_shared<ListScalar>(ArrayFromJSON(int8(), "[1, 2, 3]")),
+ std::make_shared<LargeListScalar>(ArrayFromJSON(int8(), "[1, 1, 2, 2, 3,
3]")),
+ std::make_shared<FixedSizeListScalar>(ArrayFromJSON(int8(), "[1, 2, 3,
4]")),
+ std::make_shared<StructScalar>(
+ ScalarVector{
+ std::make_shared<Int32Scalar>(2),
+ std::make_shared<Int32Scalar>(6),
+ },
+ struct_({field("min", int32()), field("max", int32())}))};
for (int64_t length : {16}) {
for (auto scalar : scalars) {
@@ -384,6 +398,40 @@ TEST_F(TestArray, TestMakeArrayFromScalar) {
}
}
+TEST_F(TestArray, TestMakeArrayFromDictionaryScalar) {
+ auto dictionary = ArrayFromJSON(utf8(), R"(["foo", "bar", "baz"])");
+ auto type = std::make_shared<DictionaryType>(int8(), utf8());
+ ASSERT_OK_AND_ASSIGN(auto value, MakeScalar(int8(), 1));
+ auto scalar = DictionaryScalar({value, dictionary}, type);
+
+ ASSERT_OK_AND_ASSIGN(auto array, MakeArrayFromScalar(scalar, 4));
+ ASSERT_OK(array->ValidateFull());
+ ASSERT_EQ(array->length(), 4);
+ ASSERT_EQ(array->null_count(), 0);
+
+ for (int i = 0; i < 4; i++) {
+ ASSERT_OK_AND_ASSIGN(auto item, array->GetScalar(i));
+ ASSERT_TRUE(item->Equals(scalar));
+ }
+}
+
+TEST_F(TestArray, TestMakeArrayFromMapScalar) {
+ auto value =
+ ArrayFromJSON(struct_({field("key", utf8(), false), field("value",
int8())}),
+ R"([{"key": "a", "value": 1}, {"key": "b", "value": 2}])");
+ auto scalar = MapScalar(value);
+
+ ASSERT_OK_AND_ASSIGN(auto array, MakeArrayFromScalar(scalar, 11));
+ ASSERT_OK(array->ValidateFull());
+ ASSERT_EQ(array->length(), 11);
+ ASSERT_EQ(array->null_count(), 0);
+
+ for (int i = 0; i < 11; i++) {
+ ASSERT_OK_AND_ASSIGN(auto item, array->GetScalar(i));
+ ASSERT_TRUE(item->Equals(scalar));
+ }
+}
+
TEST_F(TestArray, ValidateBuffersPrimitive) {
auto empty_buffer = std::make_shared<Buffer>("");
auto null_buffer = Buffer::FromString("\xff");
diff --git a/cpp/src/arrow/array/util.cc b/cpp/src/arrow/array/util.cc
index 860a62f..7016795 100644
--- a/cpp/src/arrow/array/util.cc
+++ b/cpp/src/arrow/array/util.cc
@@ -30,6 +30,7 @@
#include "arrow/array/array_base.h"
#include "arrow/array/array_dict.h"
#include "arrow/array/array_primitive.h"
+#include "arrow/array/concatenate.h"
#include "arrow/buffer.h"
#include "arrow/buffer_builder.h"
#include "arrow/extension_type.h"
@@ -296,6 +297,10 @@ class RepeatedArrayFactory {
return out_;
}
+ Status Visit(const DataType& type) {
+ return Status::NotImplemented("construction from scalar of type ",
*scalar_.type);
+ }
+
Status Visit(const BooleanType&) {
ARROW_ASSIGN_OR_RAISE(auto buffer, AllocateBitmap(length_, pool_));
BitUtil::SetBitsTo(buffer->mutable_data(), 0, length_,
@@ -305,11 +310,19 @@ class RepeatedArrayFactory {
}
template <typename T>
- enable_if_number<T, Status> Visit(const T&) {
+ enable_if_t<is_number_type<T>::value || is_fixed_size_binary_type<T>::value
||
+ is_temporal_type<T>::value,
+ Status>
+ Visit(const T&) {
auto value = checked_cast<const typename
TypeTraits<T>::ScalarType&>(scalar_).value;
return FinishFixedWidth(&value, sizeof(value));
}
+ Status Visit(const Decimal128Type&) {
+ auto value = checked_cast<const
Decimal128Scalar&>(scalar_).value.ToBytes();
+ return FinishFixedWidth(value.data(), value.size());
+ }
+
template <typename T>
enable_if_base_binary<T, Status> Visit(const T&) {
std::shared_ptr<Buffer> value =
@@ -323,15 +336,52 @@ class RepeatedArrayFactory {
return Status::OK();
}
- Status Visit(const FixedSizeBinaryType&) {
- std::shared_ptr<Buffer> value =
- checked_cast<const FixedSizeBinaryScalar&>(scalar_).value;
- return FinishFixedWidth(value->data(), value->size());
+ template <typename T>
+ enable_if_var_size_list<T, Status> Visit(const T& type) {
+ using ScalarType = typename TypeTraits<T>::ScalarType;
+ using ArrayType = typename TypeTraits<T>::ArrayType;
+
+ auto value = checked_cast<const ScalarType&>(scalar_).value;
+
+ ArrayVector values(length_, value);
+ ARROW_ASSIGN_OR_RAISE(auto value_array, Concatenate(values, pool_));
+
+ std::shared_ptr<Buffer> offsets_buffer;
+ auto size = static_cast<typename T::offset_type>(value->length());
+ RETURN_NOT_OK(CreateOffsetsBuffer(size, &offsets_buffer));
+
+ out_ =
+ std::make_shared<ArrayType>(scalar_.type, length_, offsets_buffer,
value_array);
+ return Status::OK();
}
- Status Visit(const Decimal128Type&) {
- auto value = checked_cast<const
Decimal128Scalar&>(scalar_).value.ToBytes();
- return FinishFixedWidth(value.data(), value.size());
+ Status Visit(const FixedSizeListType& type) {
+ auto value = checked_cast<const FixedSizeListScalar&>(scalar_).value;
+
+ ArrayVector values(length_, value);
+ ARROW_ASSIGN_OR_RAISE(auto value_array, Concatenate(values, pool_));
+
+ out_ = std::make_shared<FixedSizeListArray>(scalar_.type, length_,
value_array);
+ return Status::OK();
+ }
+
+ Status Visit(const MapType& type) {
+ auto map_scalar = checked_cast<const MapScalar&>(scalar_);
+ auto struct_array = checked_cast<const
StructArray*>(map_scalar.value.get());
+
+ ArrayVector keys(length_, struct_array->field(0));
+ ArrayVector values(length_, struct_array->field(1));
+
+ ARROW_ASSIGN_OR_RAISE(auto key_array, Concatenate(keys, pool_));
+ ARROW_ASSIGN_OR_RAISE(auto value_array, Concatenate(values, pool_));
+
+ std::shared_ptr<Buffer> offsets_buffer;
+ auto size = static_cast<typename
MapType::offset_type>(struct_array->length());
+ RETURN_NOT_OK(CreateOffsetsBuffer(size, &offsets_buffer));
+
+ out_ = std::make_shared<MapArray>(scalar_.type, length_,
std::move(offsets_buffer),
+ std::move(key_array),
std::move(value_array));
+ return Status::OK();
}
Status Visit(const DictionaryType& type) {
@@ -353,10 +403,6 @@ class RepeatedArrayFactory {
return Status::OK();
}
- Status Visit(const DataType& type) {
- return Status::NotImplemented("construction from scalar of type ",
*scalar_.type);
- }
-
template <typename OffsetType>
Status CreateOffsetsBuffer(OffsetType value_length, std::shared_ptr<Buffer>*
out) {
TypedBufferBuilder<OffsetType> builder(pool_);
diff --git a/cpp/src/arrow/scalar.cc b/cpp/src/arrow/scalar.cc
index 8c42f50..f8562ed 100644
--- a/cpp/src/arrow/scalar.cc
+++ b/cpp/src/arrow/scalar.cc
@@ -153,7 +153,7 @@ LargeListScalar::LargeListScalar(std::shared_ptr<Array>
value)
inline std::shared_ptr<DataType> MakeMapType(const std::shared_ptr<DataType>&
pair_type) {
ARROW_CHECK_EQ(pair_type->id(), Type::STRUCT);
ARROW_CHECK_EQ(pair_type->num_fields(), 2);
- return map(pair_type->field(0)->type(), pair_type->field(1));
+ return map(pair_type->field(0)->type(), pair_type->field(1)->type());
}
MapScalar::MapScalar(std::shared_ptr<Array> value)
diff --git a/cpp/src/arrow/scalar.h b/cpp/src/arrow/scalar.h
index eadeff5..81516eb 100644
--- a/cpp/src/arrow/scalar.h
+++ b/cpp/src/arrow/scalar.h
@@ -257,7 +257,10 @@ struct ARROW_EXPORT FixedSizeBinaryScalar : public
BinaryScalar {
template <typename T>
struct ARROW_EXPORT TemporalScalar : internal::PrimitiveScalar<T> {
using internal::PrimitiveScalar<T>::PrimitiveScalar;
- using TypeClass = T;
+ using ValueType = typename TemporalScalar<T>::ValueType;
+
+ explicit TemporalScalar(ValueType value, std::shared_ptr<DataType> type)
+ : internal::PrimitiveScalar<T>(std::move(value), type) {}
};
template <typename T>
@@ -384,7 +387,6 @@ struct ARROW_EXPORT StructScalar : public Scalar {
struct ARROW_EXPORT UnionScalar : public Scalar {
using Scalar::Scalar;
using ValueType = std::shared_ptr<Scalar>;
-
ValueType value;
UnionScalar(ValueType value, std::shared_ptr<DataType> type)
diff --git a/cpp/src/arrow/scalar_test.cc b/cpp/src/arrow/scalar_test.cc
index 8530bea..1073b08 100644
--- a/cpp/src/arrow/scalar_test.cc
+++ b/cpp/src/arrow/scalar_test.cc
@@ -559,6 +559,18 @@ TYPED_TEST(TestNumericScalar, Cast) {
}
}
+TEST(TestMapScalar, Basics) {
+ auto value =
+ ArrayFromJSON(struct_({field("key", utf8(), false), field("value",
int8())}),
+ R"([{"key": "a", "value": 1}, {"key": "b", "value": 2}])");
+ auto scalar = MapScalar(value);
+
+ auto expected_scalar_type = map(utf8(), field("value", int8()));
+
+ ASSERT_TRUE(scalar.type->Equals(expected_scalar_type));
+ ASSERT_TRUE(value->Equals(scalar.value));
+}
+
TEST(TestStructScalar, FieldAccess) {
StructScalar abc({MakeScalar(true), MakeNullScalar(int32()),
MakeScalar("hello"),
MakeNullScalar(int64())},
diff --git a/python/pyarrow/__init__.py b/python/pyarrow/__init__.py
index f7e78c8..2541855 100644
--- a/python/pyarrow/__init__.py
+++ b/python/pyarrow/__init__.py
@@ -109,7 +109,7 @@ from pyarrow.lib import (null, bool_,
schema,
unify_schemas,
Array, Tensor,
- array, chunked_array, record_batch, table, nulls,
+ array, chunked_array, record_batch, nulls, repeat,
SparseCOOTensor, SparseCSRMatrix, SparseCSCMatrix,
SparseCSFTensor,
infer_type, from_numpy_dtype,
@@ -165,7 +165,7 @@ from pyarrow.lib import (HdfsFile, NativeFile, PythonFile,
create_memory_map, have_libhdfs,
MockOutputStream, input_stream, output_stream)
-from pyarrow.lib import (ChunkedArray, RecordBatch, Table,
+from pyarrow.lib import (ChunkedArray, RecordBatch, Table, table,
concat_arrays, concat_tables)
# Exceptions
diff --git a/python/pyarrow/array.pxi b/python/pyarrow/array.pxi
index ee541ea..f337040 100644
--- a/python/pyarrow/array.pxi
+++ b/python/pyarrow/array.pxi
@@ -317,6 +317,38 @@ def asarray(values, type=None):
def nulls(size, type=None, MemoryPool memory_pool=None):
+ """
+ Create a strongly-typed Array instance with all elements null.
+
+ Parameters
+ ----------
+ size : int
+ Array length.
+ type : pyarrow.DataType, default None
+ Explicit type for the array. By default use NullType.
+ memory_pool : MemoryPool, default None
+ Arrow MemoryPool to use for allocations. Uses the default memory
+ pool is not passed.
+
+ Returns
+ -------
+ arr : Array
+
+ Examples
+ --------
+ >>> import pyarrow as pa
+ >>> pa.nulls(10)
+ <pyarrow.lib.NullArray object at 0x7ffaf04c2e50>
+ 10 nulls
+
+ >>> pa.nulls(3, pa.uint32())
+ <pyarrow.lib.UInt32Array object at 0x7ffaf04c2e50>
+ [
+ null,
+ null,
+ null
+ ]
+ """
cdef:
CMemoryPool* pool = maybe_unbox_memory_pool(memory_pool)
int64_t length = size
@@ -334,6 +366,94 @@ def nulls(size, type=None, MemoryPool memory_pool=None):
return pyarrow_wrap_array(arr)
+def repeat(value, size, MemoryPool memory_pool=None):
+ """
+ Create an Array instance whose slots are the given scalar.
+
+ Parameters
+ ----------
+ value: Scalar-like object
+ Either a pyarrow.Scalar or any python object coercible to a Scalar.
+ size : int
+ Number of times to repeat the scalar in the output Array.
+ memory_pool : MemoryPool, default None
+ Arrow MemoryPool to use for allocations. Uses the default memory
+ pool is not passed.
+
+ Returns
+ -------
+ arr : Array
+
+ Examples
+ --------
+ >>> import pyarrow as pa
+ >>> pa.repeat(10, 3)
+ <pyarrow.lib.Int64Array object at 0x7ffac03a2750>
+ [
+ 10,
+ 10,
+ 10
+ ]
+
+ >>> pa.repeat([1, 2], 2)
+ <pyarrow.lib.ListArray object at 0x7ffaf04c2e50>
+ [
+ [
+ 1,
+ 2
+ ],
+ [
+ 1,
+ 2
+ ]
+ ]
+
+ >>> pa.repeat("string", 3)
+ <pyarrow.lib.StringArray object at 0x7ffac03a2750>
+ [
+ "string",
+ "string",
+ "string"
+ ]
+
+ >>> pa.repeat(pa.scalar({'a': 1, 'b': [1, 2]}), 2)
+ <pyarrow.lib.StructArray object at 0x7ffac03a2750>
+ -- is_valid: all not null
+ -- child 0 type: int64
+ [
+ 1,
+ 1
+ ]
+ -- child 1 type: list<item: int64>
+ [
+ [
+ 1,
+ 2
+ ],
+ [
+ 1,
+ 2
+ ]
+ ]
+ """
+ cdef:
+ CMemoryPool* pool = maybe_unbox_memory_pool(memory_pool)
+ int64_t length = size
+ shared_ptr[CArray] c_array
+ shared_ptr[CScalar] c_scalar
+
+ if not isinstance(value, Scalar):
+ value = scalar(value, memory_pool=memory_pool)
+
+ c_scalar = (<Scalar> value).unwrap()
+ with nogil:
+ c_array = GetResultValue(
+ MakeArrayFromScalar(deref(c_scalar), length, pool)
+ )
+
+ return pyarrow_wrap_array(c_array)
+
+
def infer_type(values, mask=None, from_pandas=False):
"""
Attempt to infer Arrow data type that can hold the passed Python
diff --git a/python/pyarrow/includes/libarrow.pxd
b/python/pyarrow/includes/libarrow.pxd
index 7c74b2a..76203f0 100644
--- a/python/pyarrow/includes/libarrow.pxd
+++ b/python/pyarrow/includes/libarrow.pxd
@@ -203,6 +203,9 @@ cdef extern from "arrow/api.h" namespace "arrow" nogil:
CResult[shared_ptr[CArray]] MakeArrayOfNull(
const shared_ptr[CDataType]& type, int64_t length, CMemoryPool* pool)
+ CResult[shared_ptr[CArray]] MakeArrayFromScalar(
+ const CScalar& scalar, int64_t length, CMemoryPool* pool)
+
CStatus DebugPrint(const CArray& arr, int indent)
cdef cppclass CFixedWidthType" arrow::FixedWidthType"(CDataType):
diff --git a/python/pyarrow/scalar.pxi b/python/pyarrow/scalar.pxi
index 12bcda8..903faae 100644
--- a/python/pyarrow/scalar.pxi
+++ b/python/pyarrow/scalar.pxi
@@ -653,21 +653,17 @@ cdef class MapScalar(ListScalar):
Iterate over this element's values.
"""
arr = self.values
- if arr is None:
- return iter(zip(arr.field('key'), arr.field('value')))
- else:
+ if array is None:
raise StopIteration
+ for k, v in zip(arr.field('key'), arr.field('value')):
+ yield (k.as_py(), v.as_py())
def as_py(self):
"""
Return this value as a Python list.
"""
- arr = self.values
- if arr is not None:
- pairs = zip(arr.field('key'), arr.field('value'))
- return [(k.as_py(), v.as_py()) for k, v in pairs]
- else:
- return None
+ cdef CStructScalar* sp = <CStructScalar*> self.wrapped.get()
+ return list(self) if sp.is_valid else None
cdef class DictionaryScalar(Scalar):
diff --git a/python/pyarrow/tests/test_array.py
b/python/pyarrow/tests/test_array.py
index bd63ba7..27b1432 100644
--- a/python/pyarrow/tests/test_array.py
+++ b/python/pyarrow/tests/test_array.py
@@ -297,6 +297,62 @@ def test_nulls(ty):
assert arr.type == ty
+def test_array_from_scalar():
+ today = datetime.date.today()
+ now = datetime.datetime.now()
+ oneday = datetime.timedelta(days=1)
+
+ cases = [
+ (None, 1, pa.array([None])),
+ (None, 10, pa.nulls(10)),
+ (-1, 3, pa.array([-1, -1, -1], type=pa.int64())),
+ (2.71, 2, pa.array([2.71, 2.71], type=pa.float64())),
+ ("string", 4, pa.array(["string"] * 4)),
+ (
+ pa.scalar(8, type=pa.uint8()),
+ 17,
+ pa.array([8] * 17, type=pa.uint8())
+ ),
+ (pa.scalar(None), 3, pa.array([None, None, None])),
+ (pa.scalar(True), 11, pa.array([True] * 11)),
+ (today, 2, pa.array([today] * 2)),
+ (now, 10, pa.array([now] * 10)),
+ (now.time(), 9, pa.array([now.time()] * 9)),
+ (oneday, 4, pa.array([oneday] * 4)),
+ (False, 9, pa.array([False] * 9)),
+ ([1, 2], 2, pa.array([[1, 2], [1, 2]])),
+ (
+ pa.scalar([-1, 3], type=pa.large_list(pa.int8())),
+ 5,
+ pa.array([[-1, 3]] * 5, type=pa.large_list(pa.int8()))
+ ),
+ ({'a': 1, 'b': 2}, 3, pa.array([{'a': 1, 'b': 2}] * 3))
+ ]
+
+ for value, size, expected in cases:
+ arr = pa.repeat(value, size)
+ assert len(arr) == size
+ assert arr.equals(expected)
+
+ if expected.type == pa.null():
+ assert arr.null_count == size
+ else:
+ assert arr.null_count == 0
+
+
+def test_array_from_dictionary_scalar():
+ dictionary = ['foo', 'bar', 'baz']
+ arr = pa.DictionaryArray.from_arrays([2, 1, 2, 0], dictionary=dictionary)
+
+ result = pa.repeat(arr[0], 5)
+ expected = pa.DictionaryArray.from_arrays([2] * 5, dictionary=dictionary)
+ assert result.equals(expected)
+
+ result = pa.repeat(arr[3], 5)
+ expected = pa.DictionaryArray.from_arrays([0] * 5, dictionary=dictionary)
+ assert result.equals(expected)
+
+
def test_array_getitem():
arr = pa.array(range(10, 15))
lst = arr.to_pylist()
diff --git a/python/pyarrow/tests/test_scalars.py
b/python/pyarrow/tests/test_scalars.py
index c90de37..180bbc5 100644
--- a/python/pyarrow/tests/test_scalars.py
+++ b/python/pyarrow/tests/test_scalars.py
@@ -47,6 +47,8 @@ import pyarrow as pa
pa.LargeListValue),
(datetime.date.today(), None, pa.Date32Scalar, pa.Date32Value),
(datetime.datetime.now(), None, pa.TimestampScalar, pa.TimestampValue),
+ (datetime.datetime.now().time(), None, pa.Time64Scalar, pa.Time64Value),
+ (datetime.timedelta(days=1), None, pa.DurationScalar, pa.DurationValue),
({'a': 1, 'b': [1, 2]}, None, pa.StructScalar, pa.StructValue)
])
def test_basics(value, ty, klass, deprecated):
@@ -459,6 +461,15 @@ def test_map():
assert isinstance(s, pa.MapScalar)
assert isinstance(s.values, pa.Array)
assert repr(s) == "<pyarrow.MapScalar: [('a', 1), ('b', 2)]>"
+ assert s.values.to_pylist() == [
+ {'key': 'a', 'value': 1},
+ {'key': 'b', 'value': 2}
+ ]
+
+ # test iteration
+ for i, j in zip(s, v):
+ assert i == j
+
assert s.as_py() == v
assert s[1] == (
pa.scalar('b', type=pa.string()),