syvain-metrics-api-client 0.0.332__tar.gz → 0.0.341__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: syvain-metrics-api-client
3
- Version: 0.0.332
3
+ Version: 0.0.341
4
4
  Summary: Typed Python client for the Syvain Metrics REST API
5
+ Requires-Dist: jcs>=0.2.1
5
6
  Requires-Dist: niquests>=3.16.0
6
7
  Requires-Dist: pydantic>=2.13.3
7
8
  Requires-Dist: typing-extensions>=4.15.0
@@ -18,6 +19,14 @@ Use this typed Python client to find experiments and read stored metrics from
18
19
  [Syvain Metrics](https://metrics.syvain.com/). To send metrics from a training
19
20
  or evaluation job, use `syvain-metrics-collector` instead.
20
21
 
22
+ `create_annotation()` accepts text up to 16,000 characters and metadata up to
23
+ 64 KiB, or 65,536 UTF-8 bytes, of compact JSON. Keys, nested values, and JSON
24
+ punctuation count toward the metadata limit. Validation fails before any HTTP
25
+ request. The SDK counts bytes using the API's JavaScript number formatting.
26
+ The API also enforces the cap. Store larger data in an artifact and
27
+ include its path or URL in the annotation. Existing larger annotations remain
28
+ readable.
29
+
21
30
  ## Install
22
31
 
23
32
  ```bash
@@ -34,7 +43,6 @@ from syvain_metrics_api_client import SyvainMetricsApiClient
34
43
 
35
44
  with SyvainMetricsApiClient("local", timeout=60.0) as client:
36
45
  experiments = client.list_experiments(
37
- status="done",
38
46
  slug="mamba-run-001",
39
47
  limit=1,
40
48
  ).experiments
@@ -4,6 +4,14 @@ Use this typed Python client to find experiments and read stored metrics from
4
4
  [Syvain Metrics](https://metrics.syvain.com/). To send metrics from a training
5
5
  or evaluation job, use `syvain-metrics-collector` instead.
6
6
 
7
+ `create_annotation()` accepts text up to 16,000 characters and metadata up to
8
+ 64 KiB, or 65,536 UTF-8 bytes, of compact JSON. Keys, nested values, and JSON
9
+ punctuation count toward the metadata limit. Validation fails before any HTTP
10
+ request. The SDK counts bytes using the API's JavaScript number formatting.
11
+ The API also enforces the cap. Store larger data in an artifact and
12
+ include its path or URL in the annotation. Existing larger annotations remain
13
+ readable.
14
+
7
15
  ## Install
8
16
 
9
17
  ```bash
@@ -20,7 +28,6 @@ from syvain_metrics_api_client import SyvainMetricsApiClient
20
28
 
21
29
  with SyvainMetricsApiClient("local", timeout=60.0) as client:
22
30
  experiments = client.list_experiments(
23
- status="done",
24
31
  slug="mamba-run-001",
25
32
  limit=1,
26
33
  ).experiments
@@ -1,10 +1,11 @@
1
1
  [project]
2
2
  name = "syvain-metrics-api-client"
3
- version = "0.0.332"
3
+ version = "0.0.341"
4
4
  description = "Typed Python client for the Syvain Metrics REST API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
7
  dependencies = [
8
+ "jcs>=0.2.1",
8
9
  "niquests>=3.16.0",
9
10
  "pydantic>=2.13.3",
10
11
  "typing-extensions>=4.15.0",
@@ -1,10 +1,15 @@
1
1
  [project]
2
2
  name = "syvain-metrics-api-client"
3
- version = "0.0.332"
3
+ version = "0.0.341"
4
4
  description = "Typed Python client for the Syvain Metrics REST API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
- dependencies = ["niquests>=3.16.0", "pydantic>=2.13.3", "typing-extensions>=4.15.0"]
7
+ dependencies = [
8
+ "jcs>=0.2.1",
9
+ "niquests>=3.16.0",
10
+ "pydantic>=2.13.3",
11
+ "typing-extensions>=4.15.0",
12
+ ]
8
13
 
9
14
  [project.optional-dependencies]
10
15
  dev = ["pytest>=8.0.0", "ruff>=0.15.12", "ty>=0.0.34"]
@@ -795,38 +795,24 @@ class SyvainMetricsApiClient:
795
795
  def list_experiments(
796
796
  self,
797
797
  *,
798
- status: str | None = None,
799
798
  slug: str | None = None,
800
799
  search: str | None = None,
801
- from_ms: int | None = None,
802
- to_ms: int | None = None,
803
800
  limit: int | None = None,
804
801
  ) -> ExperimentsResponse:
805
- """Return experiments that match the supplied filters.
802
+ """Return a bounded page ordered by most recent directory update.
806
803
 
807
804
  Args:
808
- status: Optional experiment status filter.
809
805
  slug: Optional exact slug filter.
810
- search: Optional text search.
811
- from_ms: Optional lower timestamp bound in Unix milliseconds.
812
- to_ms: Optional upper timestamp bound in Unix milliseconds.
806
+ search: Optional case-insensitive substring in the slug.
813
807
  limit: Optional maximum number of returned experiments.
814
-
815
- Raises:
816
- ValueError: If a timestamp bound is not a safe non-negative integer.
817
808
  """
818
- from_ms = _validate_timestamp_query_bound(from_ms, field="from_ms")
819
- to_ms = _validate_timestamp_query_bound(to_ms, field="to_ms")
820
809
  return self._request_model(
821
810
  "GET",
822
811
  "/api/v1/experiments",
823
812
  ExperimentsResponse,
824
813
  query={
825
- "status": status,
826
814
  "slug": slug,
827
815
  "search": search,
828
- "from": from_ms,
829
- "to": to_ms,
830
816
  "limit": limit,
831
817
  },
832
818
  context="list_experiments",
@@ -4,6 +4,7 @@ import json
4
4
  import math
5
5
  from typing import Literal, cast
6
6
 
7
+ import jcs
7
8
  from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
8
9
  from typing_extensions import Self, TypeAliasType
9
10
 
@@ -28,6 +29,7 @@ CAMEL_OUTPUT_MODEL_CONFIG = ConfigDict(extra="allow", populate_by_name=True)
28
29
 
29
30
  MAX_SAFE_INTEGER = 9_007_199_254_740_991
30
31
  MAX_METRIC_STEP = MAX_SAFE_INTEGER - 1
32
+ MAX_ANNOTATION_METADATA_JSON_BYTES = 65_536
31
33
  METRIC_NAME_CONTRACT_DESCRIPTION = (
32
34
  "A nonempty printable ASCII metric name, at most 256 bytes raw and 512 bytes "
33
35
  "after canonical s-prefixed percent encoding."
@@ -588,7 +590,7 @@ class IngestCreateInput(BaseModel):
588
590
 
589
591
 
590
592
  class AnnotationCreateInput(BaseModel):
591
- """Validated annotation text and JSON metadata."""
593
+ """Validated annotation text and at most 64 KiB of compact JSON metadata."""
592
594
 
593
595
  model_config = INPUT_MODEL_CONFIG
594
596
 
@@ -598,7 +600,17 @@ class AnnotationCreateInput(BaseModel):
598
600
  @field_validator("metadata")
599
601
  @classmethod
600
602
  def validate_metadata(cls, value: JsonObject) -> JsonObject:
601
- return _validate_finite_metadata(value)
603
+ _validate_finite_metadata(value)
604
+ # JCS uses the API's JavaScript number formatting. Python json.dumps
605
+ # would count 1e-5 as five bytes, but JSON.stringify writes seven.
606
+ size = len(jcs.canonicalize(value))
607
+ if size > MAX_ANNOTATION_METADATA_JSON_BYTES:
608
+ raise ValueError(
609
+ f"Annotation metadata is {size} UTF-8 bytes; the limit is "
610
+ f"{MAX_ANNOTATION_METADATA_JSON_BYTES} bytes of compact JSON. "
611
+ "Store larger data in an artifact and include its path or URL."
612
+ )
613
+ return value
602
614
 
603
615
 
604
616
  class IngestionKeyCreateInput(BaseModel):