| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3321deb commit 5c4b847
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,11 @@ All notable changes to the [Nucleus Python Client](https://github.com/scaleapi/n | |||
| 5 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | |
| 6 | 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | |
| 7 | 7 | ||
| 8 | + ## [0.18.2](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.18.2) - 2026-05-08 | ||
| 9 | + | ||
| 10 | + ### Added | ||
| 11 | + - Dataset tags are now exposed through the SDK so customers can identify datasets labeled by Scale vs other vendors. `Dataset.info()` now returns a `tags` field, and `Dataset` exposes `get_tags()`, `add_tags()`, and `remove_tags()` methods. | ||
| 12 | + | ||
| 8 | 13 | ## [0.18.1](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.18.1) - 2026-05-05 | |
| 9 | 14 | ||
| 10 | 15 | ### Changed | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,12 @@ | |||
| 1 | - from typing import Any, Dict, List, Optional | ||
| 1 | + from typing import TYPE_CHECKING, Any, Dict, List, Optional | ||
| 2 | + | ||
| 3 | + if TYPE_CHECKING: | ||
| 4 | + from pydantic.v1 import validator | ||
| 5 | + else: | ||
| 6 | + try: | ||
| 7 | + from pydantic.v1 import validator | ||
| 8 | + except ImportError: | ||
| 9 | + from pydantic import validator | ||
| 2 | 10 | ||
| 3 | 11 | from nucleus.pydantic_base import DictCompatibleModel | |
| 4 | 12 | ||
@@ -14,6 +22,7 @@ class DatasetInfo(DictCompatibleModel): | |||
| 14 | 22 | slice_ids: List :class:`Slice` IDs associated with the :class:`Dataset` | |
| 15 | 23 | annotation_metadata_schema: Dict defining annotation-level metadata schema. | |
| 16 | 24 | item_metadata_schema: Dict defining item metadata schema. | |
| 25 | + tags: List of tags associated with the :class:`Dataset`. | ||
| 17 | 26 | """ | |
| 18 | 27 | ||
| 19 | 28 | dataset_id: str | |
@@ -24,3 +33,8 @@ class DatasetInfo(DictCompatibleModel): | |||
| 24 | 33 | # TODO: Expand the following into pydantic models to formalize schema | |
| 25 | 34 | annotation_metadata_schema: Optional[Dict[str, Any]] = None | |
| 26 | 35 | item_metadata_schema: Optional[Dict[str, Any]] = None | |
| 36 | + tags: List[str] = [] | ||
| 37 | + | ||
| 38 | + @validator("tags", pre=True, always=True) # pylint: disable=used-before-assignment | ||
| 39 | + def coerce_null_tags(cls, v): # pylint: disable=no-self-argument | ||
| 40 | + return v if v is not None else [] | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -433,6 +433,49 @@ def info(self) -> DatasetInfo: | |||
| 433 | 433 | dataset_info = DatasetInfo.parse_obj(response) | |
| 434 | 434 | return dataset_info | |
| 435 | 435 | ||
| 436 | + def get_tags(self) -> List[str]: | ||
| 437 | + """Fetches tags associated with the dataset. | ||
| 438 | + | ||
| 439 | + Returns: | ||
| 440 | + List of tag strings associated with this dataset. | ||
| 441 | + """ | ||
| 442 | + response = self._client.make_request( | ||
| 443 | + {}, f"dataset/{self.id}/tags", requests.get | ||
| 444 | + ) | ||
| 445 | + return response["tags"] | ||
| 446 | + | ||
| 447 | + def add_tags(self, tags: List[str]) -> List[str]: | ||
| 448 | + """Adds tags to the dataset. | ||
| 449 | + | ||
| 450 | + Args: | ||
| 451 | + tags: List of tag strings to add. | ||
| 452 | + | ||
| 453 | + Returns: | ||
| 454 | + Updated list of all tags on the dataset. | ||
| 455 | + """ | ||
| 456 | + if isinstance(tags, str): | ||
| 457 | + raise TypeError("tags must be a list of strings, not a single string") | ||
| 458 | + response = self._client.make_request( | ||
| 459 | + {"tags": tags}, f"dataset/{self.id}/tags", requests.post | ||
| 460 | + ) | ||
| 461 | + return response["tags"] | ||
| 462 | + | ||
| 463 | + def remove_tags(self, tags: List[str]) -> List[str]: | ||
| 464 | + """Removes tags from the dataset. | ||
| 465 | + | ||
| 466 | + Args: | ||
| 467 | + tags: List of tag strings to remove. | ||
| 468 | + | ||
| 469 | + Returns: | ||
| 470 | + Updated list of remaining tags on the dataset. | ||
| 471 | + """ | ||
| 472 | + if isinstance(tags, str): | ||
| 473 | + raise TypeError("tags must be a list of strings, not a single string") | ||
| 474 | + response = self._client.make_request( | ||
| 475 | + {"tags": tags}, f"dataset/{self.id}/tags", requests.delete | ||
| 476 | + ) | ||
| 477 | + return response["tags"] | ||
| 478 | + | ||
| 436 | 479 | @deprecated( | |
| 437 | 480 | "Model runs have been deprecated and will be removed. Use a Model instead" | |
| 438 | 481 | ) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,7 +25,7 @@ ignore = ["E501", "E741", "E731", "F401"] # Easy ignore for getting it running | |||
| 25 | 25 | ||
| 26 | 26 | [tool.poetry] | |
| 27 | 27 | name = "scale-nucleus" | |
| 28 | - version = "0.18.1" | ||
| 28 | + version = "0.18.2" | ||
| 29 | 29 | description = "The official Python client library for Nucleus, the Data Platform for AI" | |
| 30 | 30 | license = "MIT" | |
| 31 | 31 | authors = ["Scale AI Nucleus Team <nucleusapi@scaleapi.com>"] | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -257,6 +257,41 @@ def test_dataset_slices(CLIENT, dataset): | |||
| 257 | 257 | # TODO(gunnar): Test slice items -> Split up info! | |
| 258 | 258 | ||
| 259 | 259 | ||
| 260 | + def test_dataset_tags(CLIENT, dataset): | ||
| 261 | + # Fresh dataset should have no tags | ||
| 262 | + assert dataset.get_tags() == [] | ||
| 263 | + | ||
| 264 | + # Add tags | ||
| 265 | + updated = dataset.add_tags(["Labeled by: Scale", "production"]) | ||
| 266 | + assert "Labeled by: Scale" in updated | ||
| 267 | + assert "production" in updated | ||
| 268 | + | ||
| 269 | + # Info should include tags | ||
| 270 | + info = dataset.info() | ||
| 271 | + assert "Labeled by: Scale" in info.tags | ||
| 272 | + assert "production" in info.tags | ||
| 273 | + | ||
| 274 | + # Adding duplicate tags is idempotent | ||
| 275 | + updated2 = dataset.add_tags(["production", "v2"]) | ||
| 276 | + assert "production" in updated2 | ||
| 277 | + assert "v2" in updated2 | ||
| 278 | + | ||
| 279 | + # Remove tags | ||
| 280 | + remaining = dataset.remove_tags(["production"]) | ||
| 281 | + assert "production" not in remaining | ||
| 282 | + assert "Labeled by: Scale" in remaining | ||
| 283 | + | ||
| 284 | + # Removing non-existent tags is idempotent | ||
| 285 | + remaining2 = dataset.remove_tags(["nonexistent"]) | ||
| 286 | + assert remaining2 == remaining | ||
| 287 | + | ||
| 288 | + # String argument should raise TypeError | ||
| 289 | + with pytest.raises(TypeError): | ||
| 290 | + dataset.add_tags("not a list") | ||
| 291 | + with pytest.raises(TypeError): | ||
| 292 | + dataset.remove_tags("not a list") | ||
| 293 | + | ||
| 294 | + | ||
| 260 | 295 | def test_dataset_append_local(CLIENT, dataset): | |
| 261 | 296 | ds_items_local_error = [ | |
| 262 | 297 | DatasetItem( | |
| Back | FazBrowse Home | New Git URL |
0 commit comments