Module: OpenAI::Internal::Type::Converter Private

Extended by:
Util::SorbetRuntimeSupport
Included in:
ArrayOf, BaseModel, Boolean, Enum, FileInput, HashOf, Union, Unknown
Defined in:
lib/openai/internal/type/converter.rb

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::SorbetRuntimeSupport

const_missing, define_sorbet_constant!, sorbet_constant_defined?, to_sorbet_type, to_sorbet_type

Class Method Details

.coerce(target, value, state: {strictness: true, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Based on ‘target`, transform `value` into `target`, to the extent possible:

  1. if the given ‘value` conforms to `target` already, return the given `value`

  2. if it’s possible and safe to convert the given ‘value` to `target`, then the converted value

  3. otherwise, the given ‘value` unaltered

The coercion process is subject to improvement between minor release versions. See docs.pydantic.dev/latest/concepts/unions/#smart-mode

coercion strategy when we have to decide between multiple possible conversion targets:

  • ‘true`: the conversion must be exact, with minimum coercion.

  • ‘false`: the conversion can be approximate, with some coercion.

  • ‘:strong`: the conversion must be exact, with no coercion, and raise an error if not possible.

The ‘exactness` is `Hash` with keys being one of `yes`, `no`, or `maybe`. For any given conversion attempt, the exactness will be updated based on how closely the value recursively matches the target type:

  • ‘yes`: the value can be converted to the target type with minimum coercion.

  • ‘maybe`: the value can be converted to the target type with some reasonable coercion.

  • ‘no`: the value cannot be converted to the target type.

See implementation below for more details.

@option state [Boolean, :strong] :strictness

@option state [Hash{Symbol=>Object}] :exactness

@option state [Integer] :branched

Parameters:

  • target (OpenAI::Internal::Type::Converter, Class)
  • value (Object)
  • state (Hash{Symbol=>Object}) (defaults to: {strictness: true, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0})

    The ‘strictness` is one of `true`, `false`, or `:strong`. This informs the

Returns:

  • (Object)


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/openai/internal/type/converter.rb', line 140

def coerce(
  target,
  value,
  state: {strictness: true, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0}
)
  # rubocop:disable Lint/SuppressedException
  # rubocop:disable Metrics/BlockNesting
  strictness, exactness = state.fetch_values(:strictness, :exactness)

  case target
  in OpenAI::Internal::Type::Converter
    return target.coerce(value, state: state)
  in Class
    if value.is_a?(target)
      exactness[:yes] += 1
      return value
    end

    case target
    in -> { _1 <= NilClass }
      exactness[value.nil? ? :yes : :maybe] += 1
      return nil
    in -> { _1 <= Integer }
      if value.is_a?(Integer)
        exactness[:yes] += 1
        return value
      elsif strictness == :strong && Integer(value, exception: false) != value
        message = "no implicit conversion of #{value.class} into #{target.inspect}"
        raise value.is_a?(Numeric) ? ArgumentError.new(message) : TypeError.new(message)
      else
        Kernel.then do
          return Integer(value).tap { exactness[:maybe] += 1 }
        rescue ArgumentError, TypeError
        end
      end
    in -> { _1 <= Float }
      if value.is_a?(Numeric)
        exactness[:yes] += 1
        return Float(value)
      elsif strictness == :strong
        message = "no implicit conversion of #{value.class} into #{target.inspect}"
        raise TypeError.new(message)
      else
        Kernel.then do
          return Float(value).tap { exactness[:maybe] += 1 }
        rescue ArgumentError, TypeError
        end
      end
    in -> { _1 <= String }
      case value
      in String | Symbol | Numeric
        exactness[value.is_a?(Numeric) ? :maybe : :yes] += 1
        return value.to_s
      in StringIO
        exactness[:yes] += 1
        return value.string
      else
        if strictness == :strong
          message = "no implicit conversion of #{value.class} into #{target.inspect}"
          raise TypeError.new(message)
        end
      end
    in -> { _1 <= Date || _1 <= Time }
      Kernel.then do
        return target.parse(value).tap { exactness[:yes] += 1 }
      rescue ArgumentError, TypeError => e
        raise e if strictness == :strong
      end
    in -> { _1 <= StringIO } if value.is_a?(String)
      exactness[:yes] += 1
      return StringIO.new(value.b)
    else
    end
  in Symbol
    case value
    in Symbol | String
      if value.to_sym == target
        exactness[:yes] += 1
        return target
      else
        exactness[:maybe] += 1
        return value
      end
    else
      if strictness == :strong
        message = "cannot convert non-matching #{value.class} into #{target.inspect}"
        raise ArgumentError.new(message)
      end
    end
  else
  end

  exactness[:no] += 1
  value
  # rubocop:enable Metrics/BlockNesting
  # rubocop:enable Lint/SuppressedException
end

.dump(target, value, state: {can_retry: true}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • target (OpenAI::Internal::Type::Converter, Class)
  • value (Object)
  • state (Hash{Symbol=>Object}) (defaults to: {can_retry: true})

    .

    @option state [Boolean] :can_retry

Returns:

  • (Object)


249
250
251
252
253
254
255
256
# File 'lib/openai/internal/type/converter.rb', line 249

def dump(target, value, state: {can_retry: true})
  case target
  in OpenAI::Internal::Type::Converter
    target.dump(value, state: state)
  else
    OpenAI::Internal::Type::Unknown.dump(value, state: state)
  end
end

.inspect(target, depth:) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • target (Object)
  • depth (Integer)

Returns:

  • (String)


264
265
266
267
268
269
270
271
# File 'lib/openai/internal/type/converter.rb', line 264

def inspect(target, depth:)
  case target
  in OpenAI::Internal::Type::Converter
    target.inspect(depth: depth.succ)
  else
    target.inspect
  end
end

.type_info(spec) ⇒ Proc

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • spec (Hash{Symbol=>Object}, Proc, OpenAI::Internal::Type::Converter, Class)

    .

    @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const

    @option spec [Proc] :enum

    @option spec [Proc] :union

    @option spec [Boolean] :“nil?”

Returns:

  • (Proc)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/openai/internal/type/converter.rb', line 82

def type_info(spec)
  case spec
  in Proc
    spec
  in Hash
    type_info(spec.slice(:const, :enum, :union).first&.last)
  in true | false
    -> { OpenAI::Internal::Type::Boolean }
  in OpenAI::Internal::Type::Converter | Class | Symbol
    -> { spec }
  in NilClass | Integer | Float
    -> { spec.class }
  end
end

Instance Method Details

#coerce(value, state:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • value (Object)
  • state (Hash{Symbol=>Object})

    .

    @option state [Boolean, :strong] :strictness

    @option state [HashSymbol=>Object] :exactness

    @option state [Integer] :branched

Returns:

  • (Object)


25
# File 'lib/openai/internal/type/converter.rb', line 25

def coerce(value, state:) = (raise NotImplementedError)

#dump(value, state:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • value (Object)
  • state (Hash{Symbol=>Object})

    .

    @option state [Boolean] :can_retry

Returns:

  • (Object)


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/openai/internal/type/converter.rb', line 36

def dump(value, state:)
  case value
  in Array
    value.map { OpenAI::Internal::Type::Unknown.dump(_1, state: state) }
  in Hash
    value.transform_values { OpenAI::Internal::Type::Unknown.dump(_1, state: state) }
  in OpenAI::Internal::Type::BaseModel
    value.class.dump(value, state: state)
  in StringIO
    value.string
  in Pathname | IO
    state[:can_retry] = false if value.is_a?(IO)
    OpenAI::FilePart.new(value)
  in OpenAI::FilePart
    state[:can_retry] = false if value.content.is_a?(IO)
    value
  else
    value
  end
end

#inspect(depth: 0) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • depth (Integer) (defaults to: 0)

Returns:

  • (String)


62
63
64
# File 'lib/openai/internal/type/converter.rb', line 62

def inspect(depth: 0)
  super()
end