polars-df 0.4.0-x86_64-linux → 0.6.0-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
data/lib/polars/series.rb CHANGED
@@ -65,8 +65,14 @@ module Polars
65
65
  )
66
66
  .rename(name, in_place: true)
67
67
  ._s
68
- elsif values.is_a?(Array)
68
+ elsif values.is_a?(::Array)
69
69
  self._s = sequence_to_rbseries(name, values, dtype: dtype, strict: strict, dtype_if_empty: dtype_if_empty)
70
+ elsif defined?(Numo::NArray) && values.is_a?(Numo::NArray)
71
+ self._s = numo_to_rbseries(name, values, strict: strict, nan_to_null: nan_to_null)
72
+
73
+ if !dtype.nil?
74
+ self._s = self.cast(dtype, strict: true)._s
75
+ end
70
76
  else
71
77
  raise ArgumentError, "Series constructor called with unsupported type; got #{values.class.name}"
72
78
  end
@@ -90,10 +96,14 @@ module Polars
90
96
  #
91
97
  # @return [Hash]
92
98
  def flags
93
- {
99
+ out = {
94
100
  "SORTED_ASC" => _s.is_sorted_flag,
95
101
  "SORTED_DESC" => _s.is_sorted_reverse_flag
96
102
  }
103
+ if dtype.is_a?(List)
104
+ out["FAST_EXPLODE"] = _s.can_fast_explode_flag
105
+ end
106
+ out
97
107
  end
98
108
 
99
109
  # Get the inner dtype in of a List typed Series.
@@ -222,14 +232,28 @@ module Polars
222
232
  #
223
233
  # @return [Series]
224
234
  def *(other)
225
- _arithmetic(other, :mul)
235
+ if is_temporal
236
+ raise ArgumentError, "first cast to integer before multiplying datelike dtypes"
237
+ elsif other.is_a?(DataFrame)
238
+ other * self
239
+ else
240
+ _arithmetic(other, :mul)
241
+ end
226
242
  end
227
243
 
228
244
  # Performs division.
229
245
  #
230
246
  # @return [Series]
231
247
  def /(other)
232
- _arithmetic(other, :div)
248
+ if is_temporal
249
+ raise ArgumentError, "first cast to integer before dividing datelike dtypes"
250
+ end
251
+
252
+ if is_float
253
+ return _arithmetic(other, :div)
254
+ end
255
+
256
+ cast(Float64) / other
233
257
  end
234
258
 
235
259
  # Returns the modulo.
@@ -252,6 +276,16 @@ module Polars
252
276
  to_frame.select(Polars.col(name).pow(power)).to_series
253
277
  end
254
278
 
279
+ # Performs boolean not.
280
+ #
281
+ # @return [Series]
282
+ def !
283
+ if dtype == Boolean
284
+ return Utils.wrap_s(_s.not)
285
+ end
286
+ raise NotImplementedError
287
+ end
288
+
255
289
  # Performs negation.
256
290
  #
257
291
  # @return [Series]
@@ -278,7 +312,15 @@ module Polars
278
312
  return Utils.wrap_s(_s.take_with_series(_pos_idxs(item)._s))
279
313
  end
280
314
 
315
+ if item.is_a?(Series) && item.bool?
316
+ return filter(item)
317
+ end
318
+
281
319
  if item.is_a?(Integer)
320
+ if item < 0
321
+ item = len + item
322
+ end
323
+
282
324
  return _s.get_idx(item)
283
325
  end
284
326
 
@@ -297,7 +339,7 @@ module Polars
297
339
  #
298
340
  # @return [Object]
299
341
  def []=(key, value)
300
- if value.is_a?(Array)
342
+ if value.is_a?(::Array)
301
343
  if is_numeric || is_datelike
302
344
  set_at_idx(key, value)
303
345
  return
@@ -315,7 +357,7 @@ module Polars
315
357
  else
316
358
  raise Todo
317
359
  end
318
- elsif key.is_a?(Array)
360
+ elsif key.is_a?(::Array)
319
361
  s = Utils.wrap_s(sequence_to_rbseries("", key, dtype: UInt32))
320
362
  self[s] = value
321
363
  elsif key.is_a?(Range)
@@ -369,16 +411,26 @@ module Polars
369
411
  # Check if any boolean value in the column is `true`.
370
412
  #
371
413
  # @return [Boolean]
372
- def any
373
- to_frame.select(Polars.col(name).any).to_series[0]
414
+ def any?(&block)
415
+ if block_given?
416
+ apply(&block).any?
417
+ else
418
+ to_frame.select(Polars.col(name).any).to_series[0]
419
+ end
374
420
  end
421
+ alias_method :any, :any?
375
422
 
376
423
  # Check if all boolean values in the column are `true`.
377
424
  #
378
425
  # @return [Boolean]
379
- def all
380
- to_frame.select(Polars.col(name).all).to_series[0]
426
+ def all?(&block)
427
+ if block_given?
428
+ apply(&block).all?
429
+ else
430
+ to_frame.select(Polars.col(name).all).to_series[0]
431
+ end
381
432
  end
433
+ alias_method :all, :all?
382
434
 
383
435
  # Compute the logarithm to a given base.
384
436
  #
@@ -667,8 +719,8 @@ module Polars
667
719
  # # │ 0 ┆ 1 ┆ 0 │
668
720
  # # │ 0 ┆ 0 ┆ 1 │
669
721
  # # └─────┴─────┴─────┘
670
- def to_dummies(separator: "_")
671
- Utils.wrap_df(_s.to_dummies(separator))
722
+ def to_dummies(separator: "_", drop_first: false)
723
+ Utils.wrap_df(_s.to_dummies(separator, drop_first))
672
724
  end
673
725
 
674
726
  # Count the unique values in a Series.
@@ -1076,7 +1128,7 @@ module Polars
1076
1128
  # # 3
1077
1129
  # # ]
1078
1130
  def filter(predicate)
1079
- if predicate.is_a?(Array)
1131
+ if predicate.is_a?(::Array)
1080
1132
  predicate = Series.new("", predicate)
1081
1133
  end
1082
1134
  Utils.wrap_s(_s.filter(predicate._s))
@@ -1314,6 +1366,7 @@ module Polars
1314
1366
  def unique(maintain_order: false)
1315
1367
  super
1316
1368
  end
1369
+ alias_method :uniq, :unique
1317
1370
 
1318
1371
  # Take values by index.
1319
1372
  #
@@ -1535,6 +1588,7 @@ module Polars
1535
1588
  def is_in(other)
1536
1589
  super
1537
1590
  end
1591
+ alias_method :in?, :is_in
1538
1592
 
1539
1593
  # Get index values where Boolean Series evaluate `true`.
1540
1594
  #
@@ -1660,6 +1714,7 @@ module Polars
1660
1714
  end
1661
1715
  alias_method :count, :len
1662
1716
  alias_method :length, :len
1717
+ alias_method :size, :len
1663
1718
 
1664
1719
  # Cast between data types.
1665
1720
  #
@@ -1779,6 +1834,8 @@ module Polars
1779
1834
  [Date, Time].include?(dtype) || dtype.is_a?(Datetime) || dtype.is_a?(Duration)
1780
1835
  end
1781
1836
  alias_method :datelike?, :is_datelike
1837
+ alias_method :is_temporal, :is_datelike
1838
+ alias_method :temporal?, :is_datelike
1782
1839
 
1783
1840
  # Check if this Series has floating point numbers.
1784
1841
  #
@@ -2432,6 +2489,7 @@ module Polars
2432
2489
  end
2433
2490
  Utils.wrap_s(_s.apply_lambda(func, pl_return_dtype, skip_nulls))
2434
2491
  end
2492
+ alias_method :map, :apply
2435
2493
 
2436
2494
  # Shift the values by a given period.
2437
2495
  #
@@ -2759,7 +2817,8 @@ module Polars
2759
2817
  window_size,
2760
2818
  weights: nil,
2761
2819
  min_periods: nil,
2762
- center: false
2820
+ center: false,
2821
+ ddof: 1
2763
2822
  )
2764
2823
  to_frame
2765
2824
  .select(
@@ -2767,7 +2826,8 @@ module Polars
2767
2826
  window_size,
2768
2827
  weights: weights,
2769
2828
  min_periods: min_periods,
2770
- center: center
2829
+ center: center,
2830
+ ddof: ddof
2771
2831
  )
2772
2832
  )
2773
2833
  .to_series
@@ -2810,7 +2870,8 @@ module Polars
2810
2870
  window_size,
2811
2871
  weights: nil,
2812
2872
  min_periods: nil,
2813
- center: false
2873
+ center: false,
2874
+ ddof: 1
2814
2875
  )
2815
2876
  to_frame
2816
2877
  .select(
@@ -2818,7 +2879,8 @@ module Polars
2818
2879
  window_size,
2819
2880
  weights: weights,
2820
2881
  min_periods: min_periods,
2821
- center: center
2882
+ center: center,
2883
+ ddof: ddof
2822
2884
  )
2823
2885
  )
2824
2886
  .to_series
@@ -3483,7 +3545,7 @@ module Polars
3483
3545
  # # 99
3484
3546
  # # ]
3485
3547
  def extend_constant(value, n)
3486
- super
3548
+ Utils.wrap_s(_s.extend_constant(value, n))
3487
3549
  end
3488
3550
 
3489
3551
  # Flags the Series as sorted.
@@ -3527,10 +3589,17 @@ module Polars
3527
3589
  # Create an object namespace of all list related methods.
3528
3590
  #
3529
3591
  # @return [ListNameSpace]
3530
- def arr
3592
+ def list
3531
3593
  ListNameSpace.new(self)
3532
3594
  end
3533
3595
 
3596
+ # Create an object namespace of all array related methods.
3597
+ #
3598
+ # @return [ArrayNameSpace]
3599
+ def arr
3600
+ ArrayNameSpace.new(self)
3601
+ end
3602
+
3534
3603
  # Create an object namespace of all binary related methods.
3535
3604
  #
3536
3605
  # @return [BinaryNameSpace]
@@ -3637,14 +3706,39 @@ module Polars
3637
3706
  end
3638
3707
 
3639
3708
  def _comp(other, op)
3709
+ if dtype == Boolean && Utils.bool?(other) && [:eq, :neq].include?(op)
3710
+ if (other == true && op == :eq) || (other == false && op == :neq)
3711
+ return clone
3712
+ elsif (other == false && op == :eq) || (other == true && op == :neq)
3713
+ return !self
3714
+ end
3715
+ end
3716
+
3717
+ if other.is_a?(::Time) && dtype.is_a?(Datetime)
3718
+ ts = Utils._datetime_to_pl_timestamp(other, time_unit)
3719
+ f = ffi_func("#{op}_<>", Int64, _s)
3720
+ fail if f.nil?
3721
+ return Utils.wrap_s(f.call(ts))
3722
+ elsif other.is_a?(::Date) && dtype == Date
3723
+ d = Utils._date_to_pl_date(other)
3724
+ f = ffi_func("#{op}_<>", Int32, _s)
3725
+ fail if f.nil?
3726
+ return Utils.wrap_s(f.call(d))
3727
+ end
3728
+
3640
3729
  if other.is_a?(Series)
3641
3730
  return Utils.wrap_s(_s.send(op, other._s))
3642
3731
  end
3643
3732
 
3644
- if dtype == Utf8
3645
- raise Todo
3733
+ f = ffi_func("#{op}_<>", dtype, _s)
3734
+ if f.nil?
3735
+ raise NotImplementedError
3646
3736
  end
3647
- Utils.wrap_s(_s.send("#{op}_#{DTYPE_TO_FFINAME.fetch(dtype)}", other))
3737
+ Utils.wrap_s(f.call(other))
3738
+ end
3739
+
3740
+ def ffi_func(name, dtype, _s)
3741
+ _s.method(name.sub("<>", DTYPE_TO_FFINAME.fetch(dtype))) if DTYPE_TO_FFINAME.key?(dtype)
3648
3742
  end
3649
3743
 
3650
3744
  def _arithmetic(other, op)
@@ -3655,14 +3749,16 @@ module Polars
3655
3749
  return Utils.wrap_s(_s.send(op, other._s))
3656
3750
  end
3657
3751
 
3658
- if other.is_a?(::Date) || other.is_a?(::DateTime) || other.is_a?(::Time) || other.is_a?(String)
3659
- raise Todo
3660
- end
3661
- if other.is_a?(Float) && !is_float
3662
- raise Todo
3752
+ if (other.is_a?(Float) || other.is_a?(::Date) || other.is_a?(::DateTime) || other.is_a?(::Time) || other.is_a?(String)) && !is_float
3753
+ _s2 = sequence_to_rbseries(name, [other])
3754
+ return Utils.wrap_s(_s.send(op, _s2))
3663
3755
  end
3664
3756
 
3665
- Utils.wrap_s(_s.send("#{op}_#{DTYPE_TO_FFINAME.fetch(dtype)}", other))
3757
+ f = ffi_func("#{op}_<>", dtype, _s)
3758
+ if f.nil?
3759
+ raise ArgumentError, "cannot do arithmetic with series of dtype: #{dtype} and argument of type: #{other.class.name}"
3760
+ end
3761
+ Utils.wrap_s(f.call(other))
3666
3762
  end
3667
3763
 
3668
3764
  DTYPE_TO_FFINAME = {
@@ -3695,25 +3791,60 @@ module Polars
3695
3791
  values._s
3696
3792
  end
3697
3793
 
3794
+ def numo_to_rbseries(name, values, strict: true, nan_to_null: false)
3795
+ # not needed yet
3796
+ # if !values.contiguous?
3797
+ # end
3798
+
3799
+ if values.shape.length == 1
3800
+ values, dtype = numo_values_and_dtype(values)
3801
+ strict = nan_to_null if [Numo::SFloat, Numo::DFloat].include?(dtype)
3802
+ if dtype == Numo::RObject
3803
+ sequence_to_rbseries(name, values.to_a, strict: strict)
3804
+ else
3805
+ constructor = numo_type_to_constructor(dtype)
3806
+ # TODO improve performance
3807
+ constructor.call(name, values.to_a, strict)
3808
+ end
3809
+ elsif values.shape.length == 2
3810
+ raise Todo
3811
+ else
3812
+ raise Todo
3813
+ end
3814
+ end
3815
+
3816
+ def numo_values_and_dtype(values)
3817
+ [values, values.class]
3818
+ end
3819
+
3820
+ def numo_type_to_constructor(dtype)
3821
+ {
3822
+ Numo::Float32 => RbSeries.method(:new_opt_f32),
3823
+ Numo::Float64 => RbSeries.method(:new_opt_f64),
3824
+ Numo::Int8 => RbSeries.method(:new_opt_i8),
3825
+ Numo::Int16 => RbSeries.method(:new_opt_i16),
3826
+ Numo::Int32 => RbSeries.method(:new_opt_i32),
3827
+ Numo::Int64 => RbSeries.method(:new_opt_i64),
3828
+ Numo::UInt8 => RbSeries.method(:new_opt_u8),
3829
+ Numo::UInt16 => RbSeries.method(:new_opt_u16),
3830
+ Numo::UInt32 => RbSeries.method(:new_opt_u32),
3831
+ Numo::UInt64 => RbSeries.method(:new_opt_u64)
3832
+ }.fetch(dtype)
3833
+ rescue KeyError
3834
+ RbSeries.method(:new_object)
3835
+ end
3836
+
3698
3837
  def sequence_to_rbseries(name, values, dtype: nil, strict: true, dtype_if_empty: nil)
3699
3838
  ruby_dtype = nil
3700
- nested_dtype = nil
3701
3839
 
3702
3840
  if (values.nil? || values.empty?) && dtype.nil?
3703
- if dtype_if_empty
3704
- # if dtype for empty sequence could be guessed
3705
- # (e.g comparisons between self and other)
3706
- dtype = dtype_if_empty
3707
- else
3708
- # default to Float32 type
3709
- dtype = :f32
3710
- end
3841
+ dtype = dtype_if_empty || Float32
3842
+ elsif dtype == List
3843
+ ruby_dtype = ::Array
3711
3844
  end
3712
3845
 
3713
- rb_temporal_types = []
3714
- rb_temporal_types << ::Date if defined?(::Date)
3715
- rb_temporal_types << ::DateTime if defined?(::DateTime)
3716
- rb_temporal_types << ::Time if defined?(::Time)
3846
+ rb_temporal_types = [::Date, ::DateTime, ::Time]
3847
+ rb_temporal_types << ActiveSupport::TimeWithZone if defined?(ActiveSupport::TimeWithZone)
3717
3848
 
3718
3849
  value = _get_first_non_none(values)
3719
3850
  if !value.nil?
@@ -3722,9 +3853,20 @@ module Polars
3722
3853
  end
3723
3854
  end
3724
3855
 
3725
- if !dtype.nil? && Utils.is_polars_dtype(dtype) && ruby_dtype.nil?
3856
+ if !dtype.nil? && ![List, Unknown].include?(dtype) && Utils.is_polars_dtype(dtype) && ruby_dtype.nil?
3857
+ if dtype == Array && !dtype.is_a?(Array) && value.is_a?(::Array)
3858
+ dtype = Array.new(value.size)
3859
+ end
3860
+
3726
3861
  constructor = polars_type_to_constructor(dtype)
3727
3862
  rbseries = constructor.call(name, values, strict)
3863
+
3864
+ base_type = dtype.is_a?(DataType) ? dtype.class : dtype
3865
+ if [Date, Datetime, Duration, Time, Categorical, Boolean].include?(base_type)
3866
+ if rbseries.dtype != dtype
3867
+ rbseries = rbseries.cast(dtype, true)
3868
+ end
3869
+ end
3728
3870
  return rbseries
3729
3871
  else
3730
3872
  if ruby_dtype.nil?
@@ -3738,58 +3880,64 @@ module Polars
3738
3880
 
3739
3881
  # temporal branch
3740
3882
  if rb_temporal_types.include?(ruby_dtype)
3741
- # if dtype.nil?
3742
- # dtype = rb_type_to_dtype(ruby_dtype)
3743
- # elsif rb_temporal_types.include?(dtype)
3744
- # dtype = rb_type_to_dtype(dtype)
3745
- # end
3746
-
3747
- if ruby_dtype == ::Date
3748
- RbSeries.new_opt_date(name, values, strict)
3749
- elsif ruby_dtype == ::Time
3750
- RbSeries.new_opt_datetime(name, values, strict)
3751
- elsif ruby_dtype == ::DateTime
3752
- RbSeries.new_opt_datetime(name, values.map(&:to_time), strict)
3753
- else
3754
- raise Todo
3755
- end
3756
- elsif ruby_dtype == Array
3757
- if nested_dtype.nil?
3758
- nested_value = _get_first_non_none(value)
3759
- nested_dtype = nested_value.nil? ? Float : nested_value.class
3883
+ if dtype.nil?
3884
+ dtype = Utils.rb_type_to_dtype(ruby_dtype)
3885
+ elsif rb_temporal_types.include?(dtype)
3886
+ dtype = Utils.rb_type_to_dtype(dtype)
3760
3887
  end
3888
+ # TODO
3889
+ time_unit = nil
3761
3890
 
3762
- if nested_dtype == Array
3763
- raise Todo
3891
+ rb_series = RbSeries.new_from_anyvalues(name, values, strict)
3892
+ if time_unit.nil?
3893
+ s = Utils.wrap_s(rb_series)
3894
+ else
3895
+ s = Utils.wrap_s(rb_series).dt.cast_time_unit(time_unit)
3764
3896
  end
3765
-
3766
- if value.is_a?(Array)
3767
- count = 0
3768
- equal_to_inner = true
3769
- values.each do |lst|
3770
- lst.each do |vl|
3771
- equal_to_inner = vl.class == nested_dtype
3772
- if !equal_to_inner || count > 50
3773
- break
3774
- end
3775
- count += 1
3776
- end
3777
- end
3778
- if equal_to_inner
3779
- dtype = Utils.rb_type_to_dtype(nested_dtype)
3780
- # TODO rescue and fallback to new_object
3781
- return RbSeries.new_list(name, values, dtype)
3897
+ return s._s
3898
+ elsif defined?(Numo::NArray) && value.is_a?(Numo::NArray) && value.shape.length == 1
3899
+ raise Todo
3900
+ elsif ruby_dtype == ::Array
3901
+ if dtype.is_a?(Object)
3902
+ return RbSeries.new_object(name, values, strict)
3903
+ end
3904
+ if dtype
3905
+ srs = sequence_from_anyvalue_or_object(name, values)
3906
+ if dtype != srs.dtype
3907
+ srs = srs.cast(dtype, strict: false)
3782
3908
  end
3909
+ return srs
3783
3910
  end
3784
-
3785
- RbSeries.new_object(name, values, strict)
3911
+ return sequence_from_anyvalue_or_object(name, values)
3912
+ elsif ruby_dtype == Series
3913
+ return RbSeries.new_series_list(name, values.map(&:_s), strict)
3914
+ elsif ruby_dtype == RbSeries
3915
+ return RbSeries.new_series_list(name, values, strict)
3786
3916
  else
3787
- constructor = rb_type_to_constructor(value.class)
3917
+ constructor =
3918
+ if value.is_a?(String)
3919
+ if value.encoding == Encoding::UTF_8
3920
+ RbSeries.method(:new_str)
3921
+ else
3922
+ RbSeries.method(:new_binary)
3923
+ end
3924
+ elsif value.is_a?(Integer) && values.any? { |v| v.is_a?(Float) }
3925
+ # TODO improve performance
3926
+ RbSeries.method(:new_opt_f64)
3927
+ else
3928
+ rb_type_to_constructor(value.class)
3929
+ end
3788
3930
  constructor.call(name, values, strict)
3789
3931
  end
3790
3932
  end
3791
3933
  end
3792
3934
 
3935
+ def sequence_from_anyvalue_or_object(name, values)
3936
+ RbSeries.new_from_anyvalues(name, values, true)
3937
+ rescue
3938
+ RbSeries.new_object(name, values, false)
3939
+ end
3940
+
3793
3941
  POLARS_TYPE_TO_CONSTRUCTOR = {
3794
3942
  Float32 => RbSeries.method(:new_opt_f32),
3795
3943
  Float64 => RbSeries.method(:new_opt_f64),
@@ -3801,9 +3949,17 @@ module Polars
3801
3949
  UInt16 => RbSeries.method(:new_opt_u16),
3802
3950
  UInt32 => RbSeries.method(:new_opt_u32),
3803
3951
  UInt64 => RbSeries.method(:new_opt_u64),
3952
+ Decimal => RbSeries.method(:new_decimal),
3953
+ Date => RbSeries.method(:new_from_anyvalues),
3954
+ Datetime => RbSeries.method(:new_from_anyvalues),
3955
+ Duration => RbSeries.method(:new_from_anyvalues),
3956
+ Time => RbSeries.method(:new_from_anyvalues),
3804
3957
  Boolean => RbSeries.method(:new_opt_bool),
3805
3958
  Utf8 => RbSeries.method(:new_str),
3806
- Binary => RbSeries.method(:new_binary)
3959
+ Object => RbSeries.method(:new_object),
3960
+ Categorical => RbSeries.method(:new_str),
3961
+ Binary => RbSeries.method(:new_binary),
3962
+ Null => RbSeries.method(:new_null)
3807
3963
  }
3808
3964
 
3809
3965
  SYM_TYPE_TO_CONSTRUCTOR = {
@@ -3822,8 +3978,14 @@ module Polars
3822
3978
  }
3823
3979
 
3824
3980
  def polars_type_to_constructor(dtype)
3825
- if dtype.is_a?(Class) && dtype < DataType
3981
+ if dtype.is_a?(Array)
3982
+ lambda do |name, values, strict|
3983
+ RbSeries.new_array(dtype.width, dtype.inner, name, values, strict)
3984
+ end
3985
+ elsif dtype.is_a?(Class) && dtype < DataType
3826
3986
  POLARS_TYPE_TO_CONSTRUCTOR.fetch(dtype)
3987
+ elsif dtype.is_a?(DataType)
3988
+ POLARS_TYPE_TO_CONSTRUCTOR.fetch(dtype.class)
3827
3989
  else
3828
3990
  SYM_TYPE_TO_CONSTRUCTOR.fetch(dtype.to_sym)
3829
3991
  end
@@ -3834,9 +3996,9 @@ module Polars
3834
3996
  RB_TYPE_TO_CONSTRUCTOR = {
3835
3997
  Float => RbSeries.method(:new_opt_f64),
3836
3998
  Integer => RbSeries.method(:new_opt_i64),
3837
- String => RbSeries.method(:new_str),
3838
3999
  TrueClass => RbSeries.method(:new_opt_bool),
3839
- FalseClass => RbSeries.method(:new_opt_bool)
4000
+ FalseClass => RbSeries.method(:new_opt_bool),
4001
+ BigDecimal => RbSeries.method(:new_decimal)
3840
4002
  }
3841
4003
 
3842
4004
  def rb_type_to_constructor(dtype)