prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  GPL License Violation in the kserve python package
  The version of the `kserve` package that is currently on PyPI (version `0.10`) violates the GPL license because it depends on [`table-logger`](https://github.com/AleksTk/table-logger), distributed under GPLv2 (you'll see that the library is now MIT, the author updated the license just a few days ago, but hasn't released a new version with the new license yet). No GPLv2 packages should be imported given that `kserve` has an Apache 2 license.
  
  
  This was recently fixed by this PR https://github.com/kserve/kserve/pull/2673, which accidentally resolved the issue by replacing `table-logger` with `tabulate` (MIT License)
  
  cc @yuzisun @cliveseldon @jinchihe @ellistarn 
  
  Is it possible to quickly release a patch release `0.10.1` to include the above patch and make sure `kserve` is compliant with the Apache license? As it stands, any distribution and vendor using `kserve` is liable for a license violation.
  
  
  
  
  
  </issue>
  <code>
  [start of python/kserve/kserve/api/watch.py]
  1 # Copyright 2021 The KServe Authors.
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 #    http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 
  15 import time
  16 from kubernetes import client
  17 from kubernetes import watch as k8s_watch
  18 from table_logger import TableLogger
  19 
  20 from ..constants import constants
  21 from ..utils import utils
  22 
  23 
  24 def isvc_watch(name=None, namespace=None, timeout_seconds=600, generation=0):
  25     """Watch the created or patched InferenceService in the specified namespace"""
  26 
  27     if namespace is None:
  28         namespace = utils.get_default_target_namespace()
  29 
  30     tbl = TableLogger(
  31         columns='NAME,READY,PREV,LATEST,URL',
  32         colwidth={'NAME': 20, 'READY': 10, 'PREV': 25, 'LATEST': 25, 'URL': 65},
  33         border=False)
  34 
  35     stream = k8s_watch.Watch().stream(
  36         client.CustomObjectsApi().list_namespaced_custom_object,
  37         constants.KSERVE_GROUP,
  38         constants.KSERVE_V1BETA1_VERSION,
  39         namespace,
  40         constants.KSERVE_PLURAL,
  41         timeout_seconds=timeout_seconds)
  42 
  43     for event in stream:
  44         isvc = event['object']
  45         isvc_name = isvc['metadata']['name']
  46         if name and name != isvc_name:
  47             continue
  48         else:
  49             status = 'Unknown'
  50             if isvc.get('status', ''):
  51                 url = isvc['status'].get('url', '')
  52                 traffic = isvc['status'].get('components', {}).get(
  53                     'predictor', {}).get('traffic', [])
  54                 traffic_percent = 100
  55                 if constants.OBSERVED_GENERATION in isvc['status']:
  56                     observed_generation = isvc['status'][constants.OBSERVED_GENERATION]
  57                     for t in traffic:
  58                         if t["latestRevision"]:
  59                             traffic_percent = t["percent"]
  60 
  61                     if generation != 0 and observed_generation != generation:
  62                         continue
  63                     for condition in isvc['status'].get('conditions', {}):
  64                         if condition.get('type', '') == 'Ready':
  65                             status = condition.get('status', 'Unknown')
  66                     tbl(isvc_name, status, 100-traffic_percent, traffic_percent, url)
  67                     if status == 'True':
  68                         break
  69 
  70             else:
  71                 tbl(isvc_name, status, '', '', '')
  72                 # Sleep 2 to avoid status section is not generated within a very short time.
  73                 time.sleep(2)
  74                 continue
  75
  [end of python/kserve/kserve/api/watch.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/python/kserve/kserve/api/watch.py b/python/kserve/kserve/api/watch.py
  --- a/python/kserve/kserve/api/watch.py
  +++ b/python/kserve/kserve/api/watch.py
  @@ -13,9 +13,10 @@
   # limitations under the License.
   
   import time
  +
   from kubernetes import client
   from kubernetes import watch as k8s_watch
  -from table_logger import TableLogger
  +from tabulate import tabulate
   
   from ..constants import constants
   from ..utils import utils
  @@ -27,10 +28,8 @@
       if namespace is None:
           namespace = utils.get_default_target_namespace()
   
  -    tbl = TableLogger(
  -        columns='NAME,READY,PREV,LATEST,URL',
  -        colwidth={'NAME': 20, 'READY': 10, 'PREV': 25, 'LATEST': 25, 'URL': 65},
  -        border=False)
  +    headers = ['NAME', 'READY', 'PREV', 'LATEST', 'URL']
  +    table_fmt = 'plain'
   
       stream = k8s_watch.Watch().stream(
           client.CustomObjectsApi().list_namespaced_custom_object,
  @@ -63,12 +62,13 @@
                       for condition in isvc['status'].get('conditions', {}):
                           if condition.get('type', '') == 'Ready':
                               status = condition.get('status', 'Unknown')
  -                    tbl(isvc_name, status, 100-traffic_percent, traffic_percent, url)
  +                    print(tabulate([[isvc_name, status, 100 - traffic_percent, traffic_percent, url]],
  +                                   headers=headers, tablefmt=table_fmt))
                       if status == 'True':
                           break
   
               else:
  -                tbl(isvc_name, status, '', '', '')
  +                print(tabulate([[isvc_name, status, '', '', '']], headers=headers, tablefmt=table_fmt))
                   # Sleep 2 to avoid status section is not generated within a very short time.
                   time.sleep(2)
                   continue
  
verification_info: {"golden_diff": "diff --git a/python/kserve/kserve/api/watch.py b/python/kserve/kserve/api/watch.py\n--- a/python/kserve/kserve/api/watch.py\n+++ b/python/kserve/kserve/api/watch.py\n@@ -13,9 +13,10 @@\n # limitations under the License.\n \n import time\n+\n from kubernetes import client\n from kubernetes import watch as k8s_watch\n-from table_logger import TableLogger\n+from tabulate import tabulate\n \n from ..constants import constants\n from ..utils import utils\n@@ -27,10 +28,8 @@\n     if namespace is None:\n         namespace = utils.get_default_target_namespace()\n \n-    tbl = TableLogger(\n-        columns='NAME,READY,PREV,LATEST,URL',\n-        colwidth={'NAME': 20, 'READY': 10, 'PREV': 25, 'LATEST': 25, 'URL': 65},\n-        border=False)\n+    headers = ['NAME', 'READY', 'PREV', 'LATEST', 'URL']\n+    table_fmt = 'plain'\n \n     stream = k8s_watch.Watch().stream(\n         client.CustomObjectsApi().list_namespaced_custom_object,\n@@ -63,12 +62,13 @@\n                     for condition in isvc['status'].get('conditions', {}):\n                         if condition.get('type', '') == 'Ready':\n                             status = condition.get('status', 'Unknown')\n-                    tbl(isvc_name, status, 100-traffic_percent, traffic_percent, url)\n+                    print(tabulate([[isvc_name, status, 100 - traffic_percent, traffic_percent, url]],\n+                                   headers=headers, tablefmt=table_fmt))\n                     if status == 'True':\n                         break\n \n             else:\n-                tbl(isvc_name, status, '', '', '')\n+                print(tabulate([[isvc_name, status, '', '', '']], headers=headers, tablefmt=table_fmt))\n                 # Sleep 2 to avoid status section is not generated within a very short time.\n                 time.sleep(2)\n                 continue\n", "issue": "GPL License Violation in the kserve python package\nThe version of the `kserve` package that is currently on PyPI (version `0.10`) violates the GPL license because it depends on [`table-logger`](https://github.com/AleksTk/table-logger), distributed under GPLv2 (you'll see that the library is now MIT, the author updated the license just a few days ago, but hasn't released a new version with the new license yet). No GPLv2 packages should be imported given that `kserve` has an Apache 2 license.\r\n\r\n\r\nThis was recently fixed by this PR https://github.com/kserve/kserve/pull/2673, which accidentally resolved the issue by replacing `table-logger` with `tabulate` (MIT License)\r\n\r\ncc @yuzisun @cliveseldon @jinchihe @ellistarn \r\n\r\nIs it possible to quickly release a patch release `0.10.1` to include the above patch and make sure `kserve` is compliant with the Apache license? As it stands, any distribution and vendor using `kserve` is liable for a license violation.\r\n\r\n\r\n\r\n\n", "before_files": [{"content": "# Copyright 2021 The KServe Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport time\nfrom kubernetes import client\nfrom kubernetes import watch as k8s_watch\nfrom table_logger import TableLogger\n\nfrom ..constants import constants\nfrom ..utils import utils\n\n\ndef isvc_watch(name=None, namespace=None, timeout_seconds=600, generation=0):\n    \"\"\"Watch the created or patched InferenceService in the specified namespace\"\"\"\n\n    if namespace is None:\n        namespace = utils.get_default_target_namespace()\n\n    tbl = TableLogger(\n        columns='NAME,READY,PREV,LATEST,URL',\n        colwidth={'NAME': 20, 'READY': 10, 'PREV': 25, 'LATEST': 25, 'URL': 65},\n        border=False)\n\n    stream = k8s_watch.Watch().stream(\n        client.CustomObjectsApi().list_namespaced_custom_object,\n        constants.KSERVE_GROUP,\n        constants.KSERVE_V1BETA1_VERSION,\n        namespace,\n        constants.KSERVE_PLURAL,\n        timeout_seconds=timeout_seconds)\n\n    for event in stream:\n        isvc = event['object']\n        isvc_name = isvc['metadata']['name']\n        if name and name != isvc_name:\n            continue\n        else:\n            status = 'Unknown'\n            if isvc.get('status', ''):\n                url = isvc['status'].get('url', '')\n                traffic = isvc['status'].get('components', {}).get(\n                    'predictor', {}).get('traffic', [])\n                traffic_percent = 100\n                if constants.OBSERVED_GENERATION in isvc['status']:\n                    observed_generation = isvc['status'][constants.OBSERVED_GENERATION]\n                    for t in traffic:\n                        if t[\"latestRevision\"]:\n                            traffic_percent = t[\"percent\"]\n\n                    if generation != 0 and observed_generation != generation:\n                        continue\n                    for condition in isvc['status'].get('conditions', {}):\n                        if condition.get('type', '') == 'Ready':\n                            status = condition.get('status', 'Unknown')\n                    tbl(isvc_name, status, 100-traffic_percent, traffic_percent, url)\n                    if status == 'True':\n                        break\n\n            else:\n                tbl(isvc_name, status, '', '', '')\n                # Sleep 2 to avoid status section is not generated within a very short time.\n                time.sleep(2)\n                continue\n", "path": "python/kserve/kserve/api/watch.py"}]}