def python_value_to_parakeet(arg):
  if is_array(arg):
    rank = len(arg.shape)
    inputShape = arg.ctypes.shape_as(c_int32)
    inputStrides = arg.ctypes.strides_as(c_int32)
    npEltType = arg.dtype.type
    if ((npEltType not in numpy_to_c_types) or
        (npEltType not in numpy_to_parakeet_types)):
      raise Exception("Numpy element type unsupported: " + str(npType))
    ctype = numpy_to_c_types[npEltType]
    parakeetType = numpy_to_parakeet_types[npEltType]
    dataPtr = arg.ctypes.data_as(POINTER(ctype))
    parakeetVal = LibPar.mk_host_array(dataPtr, parakeetType, inputShape, rank,
      inputStrides, rank, arg.nbytes)
    return c_void_p(parakeetVal)

  elif arg is None: 
    return LibPar.mk_none_val()
  elif np.isscalar(arg) or is_zero_rank_array(arg):
    # unpack zero rank arrays into scalars 
    if is_zero_rank_array(arg):
      arg = arg[()] 
    if type(arg) in [int, np.int32]:
      return LibPar.mk_int32(arg)
    elif type(arg) ==  np.int64:
      return LibPar.mk_int64(arg)
    elif type(arg)in [float, np.float64]:
      return LibPar.mk_float64(c_double(arg))
    elif type(arg) == np.float32:
      return LibPar.mk_float32(c_float(arg))
    elif type(arg)in [bool, np.bool_]:
      return LibPar.mk_bool(c_bool(arg))
    else:
      raise Exception ("Unknown type: " + str(type(arg)))
  else:
    raise Exception ("Input not supported by Parakeet: " + str(arg))