prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Improve Dataset.from_uris methods
  When using the `from_uris` methods (such as in `SemanticSegmentationSlidingWindowGeoDataset`), it's easy to forget to pass in an important argument due to the use of kwargs. For example, size and stride are needed, and `label_vector_default_class_id` defaults to None which counterintuitively removes all the vectors. We should fix these and related problems.
  
  This issue was originally noted in https://github.com/azavea/raster-vision/pull/1476
  
  
  
  </issue>
  <code>
  [start of rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py]
  1 from typing import TYPE_CHECKING, Dict, Optional
  2 from copy import deepcopy
  3 
  4 from rastervision.core.data.vector_transformer import VectorTransformer
  5 from rastervision.core.data.vector_transformer.label_maker.filter import (
  6     create_filter)
  7 from rastervision.core.data.utils.geojson import features_to_geojson
  8 
  9 if TYPE_CHECKING:
  10     from rastervision.core.data import ClassConfig, CRSTransformer
  11 
  12 
  13 class ClassInferenceTransformer(VectorTransformer):
  14     """Infers missing class_ids from GeoJSON features.
  15 
  16         Rules:
  17             1) If class_id is in feature['properties'], use it.
  18             2) If class_config is set and class_name or label are in
  19                 feature['properties'] and in class_config, use corresponding
  20                 class_id.
  21             3) If class_id_to_filter is set and filter is true when applied to
  22                 feature, use corresponding class_id.
  23             4) Otherwise, return the default_class_id
  24     """
  25 
  26     def __init__(self,
  27                  default_class_id: Optional[int],
  28                  class_config: Optional['ClassConfig'] = None,
  29                  class_id_to_filter: Optional[Dict[int, list]] = None):
  30         self.class_config = class_config
  31         self.class_id_to_filter = class_id_to_filter
  32         self.default_class_id = default_class_id
  33 
  34         if self.class_id_to_filter is not None:
  35             self.class_id_to_filter = {}
  36             for class_id, filter_exp in class_id_to_filter.items():
  37                 self.class_id_to_filter[int(class_id)] = create_filter(
  38                     filter_exp)
  39 
  40     @staticmethod
  41     def infer_feature_class_id(
  42             feature: dict,
  43             default_class_id: Optional[int],
  44             class_config: Optional['ClassConfig'] = None,
  45             class_id_to_filter: Optional[Dict[int, list]] = None
  46     ) -> Optional[int]:
  47         """Infer the class_id for a GeoJSON feature.
  48 
  49         Rules:
  50             1) If class_id is in feature['properties'], use it.
  51             2) If class_config is set and class_name or label are in
  52                 feature['properties'] and in class_config, use corresponding
  53                 class_id.
  54             3) If class_id_to_filter is set and filter is true when applied to
  55                 feature, use corresponding class_id.
  56             4) Otherwise, return the default_class_id.
  57 
  58         Args:
  59             feature (dict): GeoJSON feature.
  60 
  61         Returns:
  62             Optional[int]: Inferred class ID.
  63         """
  64         class_id = feature.get('properties', {}).get('class_id')
  65         if class_id is not None:
  66             return class_id
  67 
  68         if class_config is not None:
  69             class_name = feature.get('properties', {}).get('class_name')
  70             if class_name in class_config.names:
  71                 return class_config.names.index(class_name)
  72 
  73             label = feature.get('properties', {}).get('label')
  74             if label in class_config.names:
  75                 return class_config.names.index(label)
  76 
  77         if class_id_to_filter is not None:
  78             for class_id, filter_fn in class_id_to_filter.items():
  79                 if filter_fn(feature):
  80                     return class_id
  81 
  82         return default_class_id
  83 
  84     def transform(self,
  85                   geojson: dict,
  86                   crs_transformer: Optional['CRSTransformer'] = None) -> dict:
  87         """Add class_id to feature properties and drop features with no class.
  88 
  89         For each feature in geojson, the class_id is inferred and is set into
  90         feature['properties']. If the class_id is None (because none of the
  91         rules apply and the default_class_id is None), the feature is dropped.
  92         """
  93         new_features = []
  94         for feature in geojson['features']:
  95             class_id = self.infer_feature_class_id(
  96                 feature,
  97                 default_class_id=self.default_class_id,
  98                 class_config=self.class_config,
  99                 class_id_to_filter=self.class_id_to_filter)
  100             if class_id is not None:
  101                 feature = deepcopy(feature)
  102                 properties = feature.get('properties', {})
  103                 properties['class_id'] = class_id
  104                 feature['properties'] = properties
  105                 new_features.append(feature)
  106         new_geojson = features_to_geojson(new_features)
  107         return new_geojson
  108
  [end of rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.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/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py b/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py
  --- a/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py
  +++ b/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py
  @@ -1,5 +1,6 @@
   from typing import TYPE_CHECKING, Dict, Optional
   from copy import deepcopy
  +import logging
   
   from rastervision.core.data.vector_transformer import VectorTransformer
   from rastervision.core.data.vector_transformer.label_maker.filter import (
  @@ -9,6 +10,8 @@
   if TYPE_CHECKING:
       from rastervision.core.data import ClassConfig, CRSTransformer
   
  +log = logging.getLogger(__name__)
  +
   
   class ClassInferenceTransformer(VectorTransformer):
       """Infers missing class_ids from GeoJSON features.
  @@ -91,6 +94,7 @@
           rules apply and the default_class_id is None), the feature is dropped.
           """
           new_features = []
  +        warned = False
           for feature in geojson['features']:
               class_id = self.infer_feature_class_id(
                   feature,
  @@ -103,5 +107,13 @@
                   properties['class_id'] = class_id
                   feature['properties'] = properties
                   new_features.append(feature)
  +            elif not warned:
  +                log.warning(
  +                    'ClassInferenceTransformer is dropping vector features because '
  +                    'class_id cannot be inferred. To avoid this behavior, '
  +                    'set default_class_id to a non-None value in '
  +                    'ClassInferenceTransformer.')
  +                warned = True
  +
           new_geojson = features_to_geojson(new_features)
           return new_geojson
  
verification_info: {"golden_diff": "diff --git a/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py b/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py\n--- a/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py\n+++ b/rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py\n@@ -1,5 +1,6 @@\n from typing import TYPE_CHECKING, Dict, Optional\n from copy import deepcopy\n+import logging\n \n from rastervision.core.data.vector_transformer import VectorTransformer\n from rastervision.core.data.vector_transformer.label_maker.filter import (\n@@ -9,6 +10,8 @@\n if TYPE_CHECKING:\n     from rastervision.core.data import ClassConfig, CRSTransformer\n \n+log = logging.getLogger(__name__)\n+\n \n class ClassInferenceTransformer(VectorTransformer):\n     \"\"\"Infers missing class_ids from GeoJSON features.\n@@ -91,6 +94,7 @@\n         rules apply and the default_class_id is None), the feature is dropped.\n         \"\"\"\n         new_features = []\n+        warned = False\n         for feature in geojson['features']:\n             class_id = self.infer_feature_class_id(\n                 feature,\n@@ -103,5 +107,13 @@\n                 properties['class_id'] = class_id\n                 feature['properties'] = properties\n                 new_features.append(feature)\n+            elif not warned:\n+                log.warning(\n+                    'ClassInferenceTransformer is dropping vector features because '\n+                    'class_id cannot be inferred. To avoid this behavior, '\n+                    'set default_class_id to a non-None value in '\n+                    'ClassInferenceTransformer.')\n+                warned = True\n+\n         new_geojson = features_to_geojson(new_features)\n         return new_geojson\n", "issue": "Improve Dataset.from_uris methods\nWhen using the `from_uris` methods (such as in `SemanticSegmentationSlidingWindowGeoDataset`), it's easy to forget to pass in an important argument due to the use of kwargs. For example, size and stride are needed, and `label_vector_default_class_id` defaults to None which counterintuitively removes all the vectors. We should fix these and related problems.\r\n\r\nThis issue was originally noted in https://github.com/azavea/raster-vision/pull/1476\r\n\r\n\n", "before_files": [{"content": "from typing import TYPE_CHECKING, Dict, Optional\nfrom copy import deepcopy\n\nfrom rastervision.core.data.vector_transformer import VectorTransformer\nfrom rastervision.core.data.vector_transformer.label_maker.filter import (\n    create_filter)\nfrom rastervision.core.data.utils.geojson import features_to_geojson\n\nif TYPE_CHECKING:\n    from rastervision.core.data import ClassConfig, CRSTransformer\n\n\nclass ClassInferenceTransformer(VectorTransformer):\n    \"\"\"Infers missing class_ids from GeoJSON features.\n\n        Rules:\n            1) If class_id is in feature['properties'], use it.\n            2) If class_config is set and class_name or label are in\n                feature['properties'] and in class_config, use corresponding\n                class_id.\n            3) If class_id_to_filter is set and filter is true when applied to\n                feature, use corresponding class_id.\n            4) Otherwise, return the default_class_id\n    \"\"\"\n\n    def __init__(self,\n                 default_class_id: Optional[int],\n                 class_config: Optional['ClassConfig'] = None,\n                 class_id_to_filter: Optional[Dict[int, list]] = None):\n        self.class_config = class_config\n        self.class_id_to_filter = class_id_to_filter\n        self.default_class_id = default_class_id\n\n        if self.class_id_to_filter is not None:\n            self.class_id_to_filter = {}\n            for class_id, filter_exp in class_id_to_filter.items():\n                self.class_id_to_filter[int(class_id)] = create_filter(\n                    filter_exp)\n\n    @staticmethod\n    def infer_feature_class_id(\n            feature: dict,\n            default_class_id: Optional[int],\n            class_config: Optional['ClassConfig'] = None,\n            class_id_to_filter: Optional[Dict[int, list]] = None\n    ) -> Optional[int]:\n        \"\"\"Infer the class_id for a GeoJSON feature.\n\n        Rules:\n            1) If class_id is in feature['properties'], use it.\n            2) If class_config is set and class_name or label are in\n                feature['properties'] and in class_config, use corresponding\n                class_id.\n            3) If class_id_to_filter is set and filter is true when applied to\n                feature, use corresponding class_id.\n            4) Otherwise, return the default_class_id.\n\n        Args:\n            feature (dict): GeoJSON feature.\n\n        Returns:\n            Optional[int]: Inferred class ID.\n        \"\"\"\n        class_id = feature.get('properties', {}).get('class_id')\n        if class_id is not None:\n            return class_id\n\n        if class_config is not None:\n            class_name = feature.get('properties', {}).get('class_name')\n            if class_name in class_config.names:\n                return class_config.names.index(class_name)\n\n            label = feature.get('properties', {}).get('label')\n            if label in class_config.names:\n                return class_config.names.index(label)\n\n        if class_id_to_filter is not None:\n            for class_id, filter_fn in class_id_to_filter.items():\n                if filter_fn(feature):\n                    return class_id\n\n        return default_class_id\n\n    def transform(self,\n                  geojson: dict,\n                  crs_transformer: Optional['CRSTransformer'] = None) -> dict:\n        \"\"\"Add class_id to feature properties and drop features with no class.\n\n        For each feature in geojson, the class_id is inferred and is set into\n        feature['properties']. If the class_id is None (because none of the\n        rules apply and the default_class_id is None), the feature is dropped.\n        \"\"\"\n        new_features = []\n        for feature in geojson['features']:\n            class_id = self.infer_feature_class_id(\n                feature,\n                default_class_id=self.default_class_id,\n                class_config=self.class_config,\n                class_id_to_filter=self.class_id_to_filter)\n            if class_id is not None:\n                feature = deepcopy(feature)\n                properties = feature.get('properties', {})\n                properties['class_id'] = class_id\n                feature['properties'] = properties\n                new_features.append(feature)\n        new_geojson = features_to_geojson(new_features)\n        return new_geojson\n", "path": "rastervision_core/rastervision/core/data/vector_transformer/class_inference_transformer.py"}]}