prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  PatsyData detection buglet
  If exog is None, then is_using_patsy data utility function returns False. It's a quick fix, but I'm starting to use patsy a bit more internally for convenience (e.g., passing in names to plotting functions rather than having to pull out the data) so I'll make a ticket.
  
  
  </issue>
  <code>
  [start of statsmodels/tools/data.py]
  1 """
  2 Compatibility tools for various data structure inputs
  3 """
  4 
  5 #TODO: question: interpret_data
  6 # looks good and could/should be merged with other check convertion functions we also have
  7 # similar also to what Nathaniel mentioned for Formula
  8 # good: if ndarray check passes then loading pandas is not triggered,
  9 
  10 
  11 import numpy as np
  12 
  13 def have_pandas():
  14     try:
  15         import pandas
  16         return True
  17     except ImportError:
  18         return False
  19     except Exception:
  20         return False
  21 
  22 def have_patsy():
  23     try:
  24         import patsy
  25         return True
  26     except ImportError:
  27         return False
  28     except Exception:
  29         return False
  30 
  31 def is_data_frame(obj):
  32     if not have_pandas():
  33         return False
  34 
  35     import pandas as pn
  36 
  37     return isinstance(obj, pn.DataFrame)
  38 
  39 def is_design_matrix(obj):
  40     if not have_patsy():
  41         return False
  42 
  43     from patsy import DesignMatrix
  44     return isinstance(obj, DesignMatrix)
  45 
  46 def _is_structured_ndarray(obj):
  47     return isinstance(obj, np.ndarray) and obj.dtype.names is not None
  48 
  49 def interpret_data(data, colnames=None, rownames=None):
  50     """
  51     Convert passed data structure to form required by estimation classes
  52 
  53     Parameters
  54     ----------
  55     data : ndarray-like
  56     colnames : sequence or None
  57         May be part of data structure
  58     rownames : sequence or None
  59 
  60     Returns
  61     -------
  62     (values, colnames, rownames) : (homogeneous ndarray, list)
  63     """
  64     if isinstance(data, np.ndarray):
  65         if _is_structured_ndarray(data):
  66             if colnames is None:
  67                 colnames = data.dtype.names
  68             values = struct_to_ndarray(data)
  69         else:
  70             values = data
  71 
  72         if colnames is None:
  73             colnames = ['Y_%d' % i for i in range(values.shape[1])]
  74     elif is_data_frame(data):
  75         # XXX: hack
  76         data = data.dropna()
  77         values = data.values
  78         colnames = data.columns
  79         rownames = data.index
  80     else: # pragma: no cover
  81         raise Exception('cannot handle other input types at the moment')
  82 
  83     if not isinstance(colnames, list):
  84         colnames = list(colnames)
  85 
  86     # sanity check
  87     if len(colnames) != values.shape[1]:
  88         raise ValueError('length of colnames does not match number '
  89                          'of columns in data')
  90 
  91     if rownames is not None and len(rownames) != len(values):
  92         raise ValueError('length of rownames does not match number '
  93                          'of rows in data')
  94 
  95     return values, colnames, rownames
  96 
  97 def struct_to_ndarray(arr):
  98     return arr.view((float, len(arr.dtype.names)))
  99 
  100 def _is_using_ndarray_type(endog, exog):
  101     return (type(endog) is np.ndarray and
  102             (type(exog) is np.ndarray or exog is None))
  103 
  104 def _is_using_ndarray(endog, exog):
  105     return (isinstance(endog, np.ndarray) and
  106             (isinstance(exog, np.ndarray) or exog is None))
  107 
  108 def _is_using_pandas(endog, exog):
  109     if not have_pandas():
  110         return False
  111     from pandas import Series, DataFrame, WidePanel
  112     klasses = (Series, DataFrame, WidePanel)
  113     return (isinstance(endog, klasses) or isinstance(exog, klasses))
  114 
  115 def _is_array_like(endog, exog):
  116     try: # do it like this in case of mixed types, ie., ndarray and list
  117         endog = np.asarray(endog)
  118         exog = np.asarray(exog)
  119         return True
  120     except:
  121         return False
  122 
  123 def _is_using_patsy(endog, exog):
  124     # we get this when a structured array is passed through a formula
  125     return is_design_matrix(endog) and is_design_matrix(exog)
  126 
  127
  [end of statsmodels/tools/data.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/statsmodels/tools/data.py b/statsmodels/tools/data.py
  --- a/statsmodels/tools/data.py
  +++ b/statsmodels/tools/data.py
  @@ -122,5 +122,6 @@
   
   def _is_using_patsy(endog, exog):
       # we get this when a structured array is passed through a formula
  -    return is_design_matrix(endog) and is_design_matrix(exog)
  +    return (is_design_matrix(endog) and
  +            (is_design_matrix(exog) or exog is None))
  
verification_info: {"golden_diff": "diff --git a/statsmodels/tools/data.py b/statsmodels/tools/data.py\n--- a/statsmodels/tools/data.py\n+++ b/statsmodels/tools/data.py\n@@ -122,5 +122,6 @@\n \n def _is_using_patsy(endog, exog):\n     # we get this when a structured array is passed through a formula\n-    return is_design_matrix(endog) and is_design_matrix(exog)\n+    return (is_design_matrix(endog) and\n+            (is_design_matrix(exog) or exog is None))\n", "issue": "PatsyData detection buglet\nIf exog is None, then is_using_patsy data utility function returns False. It's a quick fix, but I'm starting to use patsy a bit more internally for convenience (e.g., passing in names to plotting functions rather than having to pull out the data) so I'll make a ticket.\n\n", "before_files": [{"content": "\"\"\"\nCompatibility tools for various data structure inputs\n\"\"\"\n\n#TODO: question: interpret_data\n# looks good and could/should be merged with other check convertion functions we also have\n# similar also to what Nathaniel mentioned for Formula\n# good: if ndarray check passes then loading pandas is not triggered,\n\n\nimport numpy as np\n\ndef have_pandas():\n    try:\n        import pandas\n        return True\n    except ImportError:\n        return False\n    except Exception:\n        return False\n\ndef have_patsy():\n    try:\n        import patsy\n        return True\n    except ImportError:\n        return False\n    except Exception:\n        return False\n\ndef is_data_frame(obj):\n    if not have_pandas():\n        return False\n\n    import pandas as pn\n\n    return isinstance(obj, pn.DataFrame)\n\ndef is_design_matrix(obj):\n    if not have_patsy():\n        return False\n\n    from patsy import DesignMatrix\n    return isinstance(obj, DesignMatrix)\n\ndef _is_structured_ndarray(obj):\n    return isinstance(obj, np.ndarray) and obj.dtype.names is not None\n\ndef interpret_data(data, colnames=None, rownames=None):\n    \"\"\"\n    Convert passed data structure to form required by estimation classes\n\n    Parameters\n    ----------\n    data : ndarray-like\n    colnames : sequence or None\n        May be part of data structure\n    rownames : sequence or None\n\n    Returns\n    -------\n    (values, colnames, rownames) : (homogeneous ndarray, list)\n    \"\"\"\n    if isinstance(data, np.ndarray):\n        if _is_structured_ndarray(data):\n            if colnames is None:\n                colnames = data.dtype.names\n            values = struct_to_ndarray(data)\n        else:\n            values = data\n\n        if colnames is None:\n            colnames = ['Y_%d' % i for i in range(values.shape[1])]\n    elif is_data_frame(data):\n        # XXX: hack\n        data = data.dropna()\n        values = data.values\n        colnames = data.columns\n        rownames = data.index\n    else: # pragma: no cover\n        raise Exception('cannot handle other input types at the moment')\n\n    if not isinstance(colnames, list):\n        colnames = list(colnames)\n\n    # sanity check\n    if len(colnames) != values.shape[1]:\n        raise ValueError('length of colnames does not match number '\n                         'of columns in data')\n\n    if rownames is not None and len(rownames) != len(values):\n        raise ValueError('length of rownames does not match number '\n                         'of rows in data')\n\n    return values, colnames, rownames\n\ndef struct_to_ndarray(arr):\n    return arr.view((float, len(arr.dtype.names)))\n\ndef _is_using_ndarray_type(endog, exog):\n    return (type(endog) is np.ndarray and\n            (type(exog) is np.ndarray or exog is None))\n\ndef _is_using_ndarray(endog, exog):\n    return (isinstance(endog, np.ndarray) and\n            (isinstance(exog, np.ndarray) or exog is None))\n\ndef _is_using_pandas(endog, exog):\n    if not have_pandas():\n        return False\n    from pandas import Series, DataFrame, WidePanel\n    klasses = (Series, DataFrame, WidePanel)\n    return (isinstance(endog, klasses) or isinstance(exog, klasses))\n\ndef _is_array_like(endog, exog):\n    try: # do it like this in case of mixed types, ie., ndarray and list\n        endog = np.asarray(endog)\n        exog = np.asarray(exog)\n        return True\n    except:\n        return False\n\ndef _is_using_patsy(endog, exog):\n    # we get this when a structured array is passed through a formula\n    return is_design_matrix(endog) and is_design_matrix(exog)\n\n", "path": "statsmodels/tools/data.py"}]}