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()),

Reply via email to