Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions labelbox/data/annotation_types/base_annotation.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import abc
from uuid import UUID
from typing import Any, Dict, Optional
from pydantic import PrivateAttr
from labelbox import pydantic_compat

from .feature import FeatureSchema


class BaseAnnotation(FeatureSchema, abc.ABC):
""" Base annotation class. Shouldn't be directly instantiated
"""
_uuid: Optional[UUID] = PrivateAttr()
_uuid: Optional[UUID] = pydantic_compat.PrivateAttr()
extra: Dict[str, Any] = {}

def __init__(self, **data):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
except:
from typing_extensions import Literal

from pydantic import BaseModel, validator
from labelbox import pydantic_compat
from ..feature import FeatureSchema


# TODO: Replace when pydantic adds support for unions that don't coerce types
class _TempName(ConfidenceMixin, BaseModel):
class _TempName(ConfidenceMixin, pydantic_compat.BaseModel):
name: str

def dict(self, *args, **kwargs):
Expand Down Expand Up @@ -47,7 +47,7 @@ def dict(self, *args, **kwargs) -> Dict[str, str]:
return res


class Radio(ConfidenceMixin, CustomMetricsMixin, BaseModel):
class Radio(ConfidenceMixin, CustomMetricsMixin, pydantic_compat.BaseModel):
""" A classification with only one selected option allowed

>>> Radio(answer = ClassificationAnswer(name = "dog"))
Expand All @@ -66,7 +66,7 @@ class Checklist(_TempName):
answer: List[ClassificationAnswer]


class Text(ConfidenceMixin, CustomMetricsMixin, BaseModel):
class Text(ConfidenceMixin, CustomMetricsMixin, pydantic_compat.BaseModel):
""" Free form text

>>> Text(answer = "some text answer")
Expand Down
4 changes: 2 additions & 2 deletions labelbox/data/annotation_types/data/base_data.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from abc import ABC
from typing import Optional, Dict, List, Any

from pydantic import BaseModel
from labelbox import pydantic_compat


class BaseData(BaseModel, ABC):
class BaseData(pydantic_compat.BaseModel, ABC):
"""
Base class for objects representing data.
This class shouldn't directly be used
Expand Down
7 changes: 3 additions & 4 deletions labelbox/data/annotation_types/data/raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@

from PIL import Image
from google.api_core import retry
from pydantic import BaseModel
from pydantic import root_validator
from requests.exceptions import ConnectTimeout
import requests
import numpy as np

from labelbox import pydantic_compat
from labelbox.exceptions import InternalServerError
from .base_data import BaseData
from ..types import TypedArray


class RasterData(BaseModel, ABC):
class RasterData(pydantic_compat.BaseModel, ABC):
"""Represents an image or segmentation mask.
"""
im_bytes: Optional[bytes] = None
Expand Down Expand Up @@ -156,7 +155,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> str:
"One of url, im_bytes, file_path, arr must not be None.")
return self.url

@root_validator()
@pydantic_compat.root_validator()
def validate_args(cls, values):
file_path = values.get("file_path")
im_bytes = values.get("im_bytes")
Expand Down
4 changes: 2 additions & 2 deletions labelbox/data/annotation_types/data/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import requests
from requests.exceptions import ConnectTimeout
from google.api_core import retry
from pydantic import root_validator

from labelbox import pydantic_compat
from labelbox.exceptions import InternalServerError
from labelbox.typing_imports import Literal
from labelbox.utils import _NoCoercionMixin
Expand Down Expand Up @@ -90,7 +90,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> None:
"One of url, im_bytes, file_path, numpy must not be None.")
return self.url

@root_validator
@pydantic_compat.root_validator
def validate_date(cls, values):
file_path = values.get("file_path")
text = values.get("text")
Expand Down
17 changes: 8 additions & 9 deletions labelbox/data/annotation_types/data/tiled_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
from PIL import Image
from pyproj import Transformer
from pygeotile.point import Point as PygeoPoint
from pydantic import BaseModel, validator
from pydantic.class_validators import root_validator
from labelbox import pydantic_compat

from labelbox.data.annotation_types import Rectangle, Point, Line, Polygon
from .base_data import BaseData
Expand Down Expand Up @@ -41,7 +40,7 @@ class EPSG(Enum):
EPSG3857 = 3857


class TiledBounds(BaseModel):
class TiledBounds(pydantic_compat.BaseModel):
""" Bounds for a tiled image asset related to the relevant epsg.

Bounds should be Point objects.
Expand All @@ -55,7 +54,7 @@ class TiledBounds(BaseModel):
epsg: EPSG
bounds: List[Point]

@validator('bounds')
@pydantic_compat.validator('bounds')
def validate_bounds_not_equal(cls, bounds):
first_bound = bounds[0]
second_bound = bounds[1]
Expand All @@ -67,7 +66,7 @@ def validate_bounds_not_equal(cls, bounds):
return bounds

#validate bounds are within lat,lng range if they are EPSG4326
@root_validator
@pydantic_compat.root_validator
def validate_bounds_lat_lng(cls, values):
epsg = values.get('epsg')
bounds = values.get('bounds')
Expand All @@ -83,7 +82,7 @@ def validate_bounds_lat_lng(cls, values):
return values


class TileLayer(BaseModel):
class TileLayer(pydantic_compat.BaseModel):
""" Url that contains the tile layer. Must be in the format:

https://c.tile.openstreetmap.org/{z}/{x}/{y}.png
Expand All @@ -99,7 +98,7 @@ class TileLayer(BaseModel):
def asdict(self) -> Dict[str, str]:
return {"tileLayerUrl": self.url, "name": self.name}

@validator('url')
@pydantic_compat.validator('url')
def validate_url(cls, url):
xyz_format = "/{z}/{x}/{y}"
if xyz_format not in url:
Expand Down Expand Up @@ -344,7 +343,7 @@ def _validate_num_tiles(self, xstart: float, ystart: float, xend: float,
f"Max allowed tiles are {max_tiles}"
f"Increase max tiles or reduce zoom level.")

@validator('zoom_levels')
@pydantic_compat.validator('zoom_levels')
def validate_zoom_levels(cls, zoom_levels):
if zoom_levels[0] > zoom_levels[1]:
raise ValueError(
Expand All @@ -353,7 +352,7 @@ def validate_zoom_levels(cls, zoom_levels):
return zoom_levels


class EPSGTransformer(BaseModel):
class EPSGTransformer(pydantic_compat.BaseModel):
"""Transformer class between different EPSG's. Useful when wanting to project
in different formats.
"""
Expand Down
5 changes: 3 additions & 2 deletions labelbox/data/annotation_types/data/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import cv2
import numpy as np
from google.api_core import retry
from pydantic import root_validator

from .base_data import BaseData
from ..types import TypedArray

from labelbox import pydantic_compat

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -147,7 +148,7 @@ def frames_to_video(self,
out.release()
return file_path

@root_validator
@pydantic_compat.root_validator
def validate_data(cls, values):
file_path = values.get("file_path")
url = values.get("url")
Expand Down
6 changes: 3 additions & 3 deletions labelbox/data/annotation_types/feature.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Optional

from pydantic import BaseModel, root_validator
from labelbox import pydantic_compat

from .types import Cuid


class FeatureSchema(BaseModel):
class FeatureSchema(pydantic_compat.BaseModel):
"""
Class that represents a feature schema.
Could be a annotation, a subclass, or an option.
Expand All @@ -14,7 +14,7 @@ class FeatureSchema(BaseModel):
name: Optional[str] = None
feature_schema_id: Optional[Cuid] = None

@root_validator
@pydantic_compat.root_validator
def must_set_one(cls, values):
if values['feature_schema_id'] is None and values['name'] is None:
raise ValueError(
Expand Down
4 changes: 2 additions & 2 deletions labelbox/data/annotation_types/geometry/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

import geojson
import numpy as np
from pydantic import BaseModel
from labelbox import pydantic_compat

from shapely import geometry as geom


class Geometry(BaseModel, ABC):
class Geometry(pydantic_compat.BaseModel, ABC):
"""Abstract base class for geometry objects
"""
extra: Dict[str, Any] = {}
Expand Down
5 changes: 3 additions & 2 deletions labelbox/data/annotation_types/geometry/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import geojson
import numpy as np
import cv2
from pydantic import validator

from shapely.geometry import LineString as SLineString

from .point import Point
from .geometry import Geometry

from labelbox import pydantic_compat


class Line(Geometry):
"""Line annotation
Expand Down Expand Up @@ -64,7 +65,7 @@ def draw(self,
color=color,
thickness=thickness)

@validator('points')
@pydantic_compat.validator('points')
def is_geom_valid(cls, points):
if len(points) < 2:
raise ValueError(
Expand Down
5 changes: 3 additions & 2 deletions labelbox/data/annotation_types/geometry/mask.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from typing import Callable, Optional, Tuple, Union, Dict, List

import numpy as np
from pydantic.class_validators import validator
import cv2

from shapely.geometry import MultiPolygon, Polygon

from ..data import MaskData
from .geometry import Geometry

from labelbox import pydantic_compat


class Mask(Geometry):
"""Mask used to represent a single class in a larger segmentation mask
Expand Down Expand Up @@ -121,7 +122,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> str:
"""
return self.mask.create_url(signer)

@validator('color')
@pydantic_compat.validator('color')
def is_valid_color(cls, color):
if isinstance(color, (tuple, list)):
if len(color) == 1:
Expand Down
5 changes: 3 additions & 2 deletions labelbox/data/annotation_types/geometry/polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import cv2
import geojson
import numpy as np
from pydantic import validator

from shapely.geometry import Polygon as SPolygon

from .geometry import Geometry
from .point import Point

from labelbox import pydantic_compat


class Polygon(Geometry):
"""Polygon geometry
Expand Down Expand Up @@ -67,7 +68,7 @@ def draw(self,
return cv2.fillPoly(canvas, pts, color)
return cv2.polylines(canvas, pts, True, color, thickness)

@validator('points')
@pydantic_compat.validator('points')
def is_geom_valid(cls, points):
if len(points) < 3:
raise ValueError(
Expand Down
6 changes: 3 additions & 3 deletions labelbox/data/annotation_types/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Any, Callable, Dict, List, Union, Optional
import warnings

from pydantic import BaseModel, validator
from labelbox import pydantic_compat

import labelbox
from labelbox.data.annotation_types.data.tiled_image import TiledImageData
Expand All @@ -24,7 +24,7 @@
LlmResponseCreationData]


class Label(BaseModel):
class Label(pydantic_compat.BaseModel):
"""Container for holding data and annotations

>>> Label(
Expand Down Expand Up @@ -189,7 +189,7 @@ def _assign_option(self, classification: ClassificationAnnotation,
f"Unexpected type for answer found. {type(classification.value.answer)}"
)

@validator("annotations", pre=True)
@pydantic_compat.validator("annotations", pre=True)
def validate_union(cls, value):
supported = tuple([
field.type_
Expand Down
16 changes: 8 additions & 8 deletions labelbox/data/annotation_types/metrics/base.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from abc import ABC
from pydantic import ValidationError, confloat, BaseModel, validator
from pydantic.error_wrappers import ErrorWrapper
from typing import Dict, Optional, Any, Union

ConfidenceValue = confloat(ge=0, le=1)
from labelbox import pydantic_compat

ConfidenceValue = pydantic_compat.confloat(ge=0, le=1)

MIN_CONFIDENCE_SCORES = 2
MAX_CONFIDENCE_SCORES = 15


class BaseMetric(BaseModel, ABC):
class BaseMetric(pydantic_compat.BaseModel, ABC):
value: Union[Any, Dict[float, Any]]
feature_name: Optional[str] = None
subclass_name: Optional[str] = None
Expand All @@ -19,17 +19,17 @@ def dict(self, *args, **kwargs):
res = super().dict(*args, **kwargs)
return {k: v for k, v in res.items() if v is not None}

@validator('value')
@pydantic_compat.validator('value')
def validate_value(cls, value):
if isinstance(value, Dict):
if not (MIN_CONFIDENCE_SCORES <= len(value) <=
MAX_CONFIDENCE_SCORES):
raise ValidationError([
ErrorWrapper(ValueError(
raise pydantic_compat.ValidationError([
pydantic_compat.ErrorWrapper(ValueError(
"Number of confidence scores must be greater"
f" than or equal to {MIN_CONFIDENCE_SCORES} and"
f" less than or equal to {MAX_CONFIDENCE_SCORES}. Found {len(value)}"
),
loc='value')
loc='value')
], cls)
return value
Loading