code: def do_draw(self, data):
      if 0 in self.shape:
          return np.zeros(dtype=self.dtype, shape=self.shape)
  
      # Because Numpy allocates memory for strings at array creation, if we have
      # an unsized string dtype we'll fill an object array and then cast it back.
      unsized_string_dtype = (
          self.dtype.kind in ("S", "a", "U")
          and self.dtype.itemsize == 0
      )
  
      # Reset this flag for each test case to emit warnings from set_element
      # Skip the check for object or void (multi-element) dtypes
      self._report_overflow = (
          self.dtype.kind not in "OV" and not unsized_string_dtype
      )
  
      # This could legitimately be a np.empty, but the performance gains for
      # that would be so marginal that there's really not much point risking
      # undefined behaviour shenanigans.
      result = np.zeros(
          shape=self.array_size,
          dtype=object if unsized_string_dtype else self.dtype,
      )
  
      if self.fill.is_empty:
          # We have no fill value (either because the user explicitly
          # disabled it or because the default behaviour was used and our
          # elements strategy does not produce reusable values), so we must
          # generate a fully dense array with a freshly drawn value for each
          # entry.
          if self.unique:
              seen = set()
              elements = cu.many(
                  data,
                  min_size=self.array_size,
                  max_size=self.array_size,
                  average_size=self.array_size,
              )
              i = 0
              while elements.more():
                  # We assign first because this means we check for
                  # uniqueness after numpy has converted it to the relevant
                  # type for us. Because we don't increment the counter on
                  # a duplicate we will overwrite it on the next draw.
                  self.set_element(data, result, i)
                  if result[i] not in seen:
                      seen.add(result[i])
                      i += 1
                  else:
                      elements.reject()
          else:
              for i in hrange(len(result)):
                  self.set_element(data, result, i)
      else:
          # We draw numpy arrays as "sparse with an offset". We draw a
          # collection of index assignments within the array and assign
          # fresh values from our elements strategy to those indices. If at
          # the end we have not assigned every element then we draw a single
          # value from our fill strategy and use that to populate the
          # remaining positions with that strategy.
  
          elements = cu.many(
              data,
              min_size=0,
              max_size=self.array_size,
              # sqrt isn't chosen for any particularly principled reason. It
              # just grows reasonably quickly but sublinearly, and for small
              # arrays it represents a decent fraction of the array size.
              average_size=math.sqrt(self.array_size),
          )
  
          needs_fill = np.full(self.array_size, True)
          seen = set()
  
          while elements.more():
              i = cu.integer_range(data, 0, self.array_size - 1)
              if not needs_fill[i]:
                  elements.reject()
                  continue
              self.set_element(data, result, i)
              if self.unique:
                  if result[i] in seen:
                      elements.reject()
                      continue
                  else:
                      seen.add(result[i])
              needs_fill[i] = False
          if needs_fill.any():
              # We didn't fill all of the indices in the early loop, so we
              # put a fill value into the rest.
  
              # We have to do this hilarious little song and dance to work
              # around numpy's special handling of iterable values. If the
              # value here were e.g. a tuple then neither array creation
              # nor putmask would do the right thing. But by creating an
              # array of size one and then assigning the fill value as a
              # single element, we both get an array with the right value in
              # it and putmask will do the right thing by repeating the
              # values of the array across the mask.
              one_element = np.zeros(
                  shape=1,
                  dtype=object if unsized_string_dtype else self.dtype,
              )
              self.set_element(data, one_element, 0, self.fill)
              if unsized_string_dtype:
                  one_element = one_element.astype(self.dtype)
              fill_value = one_element[0]
              if self.unique:
                  try:
                      is_nan = np.isnan(fill_value)
                  except TypeError:
                      is_nan = False
  
                  if not is_nan:
                      raise InvalidArgument(
                          "Cannot fill unique array with non-NaN "
                          "value %r" % (fill_value,)
                      )
  
              np.putmask(result, needs_fill, one_element)
  
      if unsized_string_dtype:
          out = result.astype(self.dtype)
          mismatch = out != result
          if mismatch.any():
              note_deprecation(
                  "Array elements %r cannot be represented as dtype %r - instead "
                  "they becomes %r.  Use a more precise strategy, e.g. without "
                  "trailing null bytes, as this will be an error future versions."
                  % (result[mismatch], self.dtype, out[mismatch]),
                  since="2019-07-28",
              )
          result = out
  
      return result.reshape(self.shape)
  
imports: from __future__ import absolute_import, division, print_function
  import math
  import re
  from collections import namedtuple
  import numpy
  import hypothesis.internal.conjecture.utils
  import hypothesis.strategies._internal.core
  from hypothesis import Verbosity, assume
  from hypothesis._settings import note_deprecation
  from hypothesis.errors import InvalidArgument
  from hypothesis.internal.compat import PY2, hrange, integer_types, quiet_raise, string_types
  from hypothesis.internal.coverage import check_function
  from hypothesis.internal.reflection import proxies, reserved_means_kwonly_star
  from hypothesis.internal.validation import check_type, check_valid_interval
  from hypothesis.reporting import current_verbosity
  from hypothesis.strategies._internal import SearchStrategy
  from hypothesis.utils.conventions import UniqueIdentifier, not_set
label_desc: Use image node_id 3 for calling the ArrayStrategy obj's underlying member method code with example usage: obj.do_draw(data) and returns: result, np