text: # -*- coding: utf-8 -*-
  # ============================
  # Python Interface
  # ============================
  from __future__ import absolute_import, division, print_function
  import logging
  from os.path import join, realpath, dirname
  import numpy as np
  import ctypes as C
  import sys
  from pydarknet import ctypes_interface
  
  
  logger = logging.getLogger('pydarknet')
  
  
  def ensure_bytes_strings(str_list):
      # converts python3 strings into bytes
      if sys.hexversion > 0x03000000:
          return [
              str_ if not isinstance(str_, str) else bytes(str_, 'utf-8')
              for str_ in str_list
          ]
      else:
          return str_list
  
  
  def _cast_list_to_c(py_list, dtype):
      """
      Converts a python list of strings into a c array of strings
      adapted from "http://stackoverflow.com/questions/3494598/passing-a-list-of
      -strings-to-from-python-ctypes-to-c-function-expecting-char"
      Avi's code
      """
      c_arr = (dtype * len(py_list))()
      c_arr[:] = py_list
      return c_arr
  
  
  def _arrptr_to_np(c_arrptr, shape, arr_t, dtype):
      """
      Casts an array pointer from C to numpy
      Input:
          c_arrpt - an array pointer returned from C
          shape   - shape of that array pointer
          arr_t   - the ctypes datatype of c_arrptr
      Avi's code
      """
      arr_t_size = C.POINTER(C.c_char * dtype().itemsize)  # size of each item
      c_arr = C.cast(c_arrptr.astype(int), arr_t_size)  # cast to ctypes
      np_arr = np.ctypeslib.as_array(c_arr, shape)  # cast to numpy
      np_arr.dtype = dtype  # fix numpy dtype
      np_arr = np.require(np_arr, dtype=dtype, requirements=['O'])  # prevent memory leaks
      return np_arr
  
  
  def _extract_np_array(size_list, ptr_list, arr_t, arr_dtype, arr_dim):
      """
      size_list - contains the size of each output 2d array
      ptr_list  - an array of pointers to the head of each output 2d
                  array (which was allocated in C)
      arr_t     - the C pointer type
      arr_dtype - the numpy array type
      arr_dim   - the number of columns in each output 2d array
      """
      arr_list = [
          _arrptr_to_np(arr_ptr, (size, arr_dim), arr_t, arr_dtype)
          for (arr_ptr, size) in zip(ptr_list, size_list)
      ]
      return arr_list
  
  
  def _find_c_shared_library_by_device(device='cpu'):
      root_dir = realpath(join(dirname(__file__), 'lib'))
  
      if device in ['cpu']:
          libname = 'pydarknet'
      elif device in ['gpu']:
          libname = 'pydarknet_cuda'
      else:
          raise ValueError('device %r not recognized' % (device,))
  
      try:
          darknet_clib, def_cfunc = ctypes_interface.load_clib(libname, root_dir)
      except ImportError:
          if device not in ['cpu']:
              logging.info('CPU fallback for: %s' % (libname,))
              darknet_clib, def_cfunc = _find_c_shared_library_by_device()
          else:
              import warnings
  
              warnings.warn('Unable to load C library for darknet')
              darknet_clib, def_cfunc = None, None
  
      return darknet_clib, def_cfunc
  
  
  def _load_c_shared_library(METHODS, device='cpu'):
      """Loads the pydarknet dynamic library and defines its functions"""
  
      darknet_clib, def_cfunc = _find_c_shared_library_by_device(device=device)
  
      if None in [darknet_clib, def_cfunc]:
          return None, None
  
      # Load and expose methods from lib
      for method in METHODS.keys():
          def_cfunc(METHODS[method][1], method, METHODS[method][0])
  
      return darknet_clib, def_cfunc
  