Skip to content
Draft
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
5 changes: 3 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ workflows:
name: python-<< matrix.python_version>>
matrix:
parameters:
python_version: ["3.10", "3.11", "3.12", "3.13"]
python_version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
pydantic_version: ["2.12"]
httpx_version: ["0.28"]
- test:
Expand All @@ -129,7 +129,7 @@ workflows:
name: httpx-<< matrix.httpx_version >>
matrix:
parameters:
python_version: ["3.13"]
python_version: ["3.14"]
pydantic_version: ["2.12"]
httpx_version: ["0.25", "0.26", "0.27", "0.28"]
- black:
Expand All @@ -141,6 +141,7 @@ workflows:
- python-3.11
- python-3.12
- python-3.13
- python-3.14

- pydantic-2.6
- pydantic-2.7
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
tmp
test.py
venv
.idea
3 changes: 3 additions & 0 deletions foundry_sdk/_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,6 @@
from foundry_sdk._core.utils import Timeout as Timeout
from foundry_sdk._core.utils import maybe_ignore_preview as maybe_ignore_preview
from foundry_sdk._core.utils import resolve_forward_references as resolve_forward_references # NOQA
from foundry_sdk._core.utils import (
resolve_forward_references_in_module as resolve_forward_references_in_module,
) # NOQA
31 changes: 24 additions & 7 deletions foundry_sdk/_core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,23 @@
import pydantic
from typing_extensions import Annotated

RID = Annotated[
RID: typing.TypeAlias = Annotated[
str,
pydantic.StringConstraints(
pattern=r"^ri\.[a-z][a-z0-9-]*\.([a-z0-9][a-z0-9\-]*)?\.[a-z][a-z0-9-]*\.[a-zA-Z0-9._-]+$",
),
]


UUID = Annotated[
UUID: typing.TypeAlias = Annotated[
str,
pydantic.StringConstraints(
pattern=r"^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$",
),
]


Long = Annotated[
Long: typing.TypeAlias = Annotated[
int,
pydantic.PlainSerializer(
lambda value: str(value),
Expand All @@ -56,7 +56,7 @@
"""A long integer that is serialized to a string in JSON."""


AwareDatetime = Annotated[
AwareDatetime: typing.TypeAlias = Annotated[
pydantic.AwareDatetime,
pydantic.PlainSerializer(
lambda value: value.astimezone(timezone.utc).isoformat(),
Expand All @@ -69,7 +69,7 @@
"""A datetime object that enforces timezones and is always serialized to UTC."""


Timeout = Annotated[int, pydantic.Field(gt=0)]
Timeout: typing.TypeAlias = Annotated[int, pydantic.Field(gt=0)]


def remove_prefixes(text: str, prefixes: List[str]):
Expand Down Expand Up @@ -111,8 +111,25 @@ def resolve_forward_references(type_obj: Any, globalns: dict, localns: dict) ->
for arg in typing.get_args(type_obj) # type: ignore
)

setattr(type_obj, "__args__", args)
return type_obj
# Always reconstruct rather than mutating __args__ in place: on Python 3.14+
# setattr silently succeeds for Annotated types but typing.get_args() reads
# from __origin__ / __metadata__ and ignores the mutated __args__ field.
return typing.get_origin(type_obj)[args]


def resolve_forward_references_in_module(module_name: str) -> None:
"""Resolve forward references in all generic type aliases in a module.

Call as ``core.resolve_forward_references_in_module(__name__)`` at the end
of a models.py after all classes are defined. Updates the module namespace
in place so pyright's view of each TypeAlias is undisturbed.
"""
import sys

ns = vars(sys.modules[module_name])
for name, obj in list(ns.items()):
if typing.get_origin(obj) is not None:
ns[name] = resolve_forward_references(obj, ns, ns)


def assert_non_empty_string(value: str, name: str) -> None:
Expand Down
49 changes: 26 additions & 23 deletions foundry_sdk/v1/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import typing

import pydantic
import typing_extensions

from foundry_sdk import _core as core

Expand All @@ -34,7 +35,7 @@ class AttachmentType(core.ModelBase):
type: typing.Literal["attachment"] = "attachment"


Attribution = str
Attribution: typing_extensions.TypeAlias = str
"""Attribution for a request"""


Expand Down Expand Up @@ -65,11 +66,11 @@ class CipherTextType(core.ModelBase):
type: typing.Literal["cipherText"] = "cipherText"


ContentLength = core.Long
ContentLength: typing_extensions.TypeAlias = core.Long
"""ContentLength"""


ContentType = str
ContentType: typing_extensions.TypeAlias = str
"""ContentType"""


Expand All @@ -91,11 +92,11 @@ class DecimalType(core.ModelBase):
type: typing.Literal["decimal"] = "decimal"


DisplayName = str
DisplayName: typing_extensions.TypeAlias = str
"""The display name of the entity."""


DistanceUnit = typing.Literal[
DistanceUnit: typing_extensions.TypeAlias = typing.Literal[
"MILLIMETERS",
"CENTIMETERS",
"METERS",
Expand All @@ -115,14 +116,14 @@ class DoubleType(core.ModelBase):
type: typing.Literal["double"] = "double"


FilePath = str
FilePath: typing_extensions.TypeAlias = str
"""
The path to a File within Foundry. Paths are relative and must not start with a leading slash.
Examples: `my-file.txt`, `path/to/my-file.jpg`, `dataframe.snappy.parquet`.
"""


Filename = str
Filename: typing_extensions.TypeAlias = str
"""The name of a File within Foundry. Examples: `my-file.txt`, `my-file.jpg`, `dataframe.snappy.parquet`."""


Expand All @@ -132,11 +133,11 @@ class FloatType(core.ModelBase):
type: typing.Literal["float"] = "float"


FolderRid = core.RID
FolderRid: typing_extensions.TypeAlias = core.RID
"""FolderRid"""


FoundryBranch = str
FoundryBranch: typing_extensions.TypeAlias = str
"""The Foundry branch identifier, specifically its rid. Different identifier types may be used in the future as values."""


Expand All @@ -159,7 +160,7 @@ class MarkingType(core.ModelBase):
type: typing.Literal["marking"] = "marking"


MarkingTypeValue = typing.Literal["CBAC", "MANDATORY"]
MarkingTypeValue: typing_extensions.TypeAlias = typing.Literal["CBAC", "MANDATORY"]
"""
The kind of marking applied by a marking property type.
- `CBAC`: Classification-based access control markings.
Expand All @@ -173,7 +174,7 @@ class MediaReferenceType(core.ModelBase):
type: typing.Literal["mediaReference"] = "mediaReference"


MediaType = str
MediaType: typing_extensions.TypeAlias = str
"""
The [media type](https://www.iana.org/assignments/media-types/media-types.xhtml) of the file or attachment.
Examples: `application/json`, `application/pdf`, `application/octet-stream`, `image/jpeg`
Expand All @@ -186,27 +187,29 @@ class NullType(core.ModelBase):
type: typing.Literal["null"] = "null"


OperationScope = str
OperationScope: typing_extensions.TypeAlias = str
"""OperationScope"""


PageSize = int
PageSize: typing_extensions.TypeAlias = int
"""The page size to use for the endpoint."""


PageToken = str
PageToken: typing_extensions.TypeAlias = str
"""
The page token indicates where to start paging. This should be omitted from the first page's request.
To fetch the next page, clients should take the value from the `nextPageToken` field of the previous response
and use it to populate the `pageToken` field of the next request.
"""


PreviewMode = bool
PreviewMode: typing_extensions.TypeAlias = bool
"""Enables the use of preview functionality."""


ReleaseStatus = typing.Literal["ACTIVE", "ENDORSED", "EXPERIMENTAL", "DEPRECATED"]
ReleaseStatus: typing_extensions.TypeAlias = typing.Literal[
"ACTIVE", "ENDORSED", "EXPERIMENTAL", "DEPRECATED"
]
"""The release status of the entity."""


Expand All @@ -216,7 +219,7 @@ class ShortType(core.ModelBase):
type: typing.Literal["short"] = "short"


SizeBytes = core.Long
SizeBytes: typing_extensions.TypeAlias = core.Long
"""The size of the file or attachment in bytes."""


Expand All @@ -226,7 +229,7 @@ class StringType(core.ModelBase):
type: typing.Literal["string"] = "string"


StructFieldName = str
StructFieldName: typing_extensions.TypeAlias = str
"""The name of a field in a `Struct`."""


Expand All @@ -236,15 +239,15 @@ class TimestampType(core.ModelBase):
type: typing.Literal["timestamp"] = "timestamp"


TotalCount = core.Long
TotalCount: typing_extensions.TypeAlias = core.Long
"""The total number of items across all pages."""


TraceParent = str
TraceParent: typing_extensions.TypeAlias = str
"""The W3C Trace Context `traceparent` header value used to propagate distributed tracing information for Foundry telemetry. See https://www.w3.org/TR/trace-context/#traceparent-header for more details. Note the 16 byte trace ID encoded in the header must be derived from a time based uuid to be used within Foundry."""


TraceState = str
TraceState: typing_extensions.TypeAlias = str
"""The W3C Trace Context `tracestate` header value, which is used to propagate vendor specific distributed tracing information for Foundry telemetry. See https://www.w3.org/TR/trace-context/#tracestate-header for more details."""


Expand All @@ -256,11 +259,11 @@ class UnsupportedType(core.ModelBase):
type: typing.Literal["unsupported"] = "unsupported"


UnsupportedTypeParamKey = str
UnsupportedTypeParamKey: typing_extensions.TypeAlias = str
"""UnsupportedTypeParamKey"""


UnsupportedTypeParamValue = str
UnsupportedTypeParamValue: typing_extensions.TypeAlias = str
"""UnsupportedTypeParamValue"""


Expand Down
17 changes: 10 additions & 7 deletions foundry_sdk/v1/datasets/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import typing

import pydantic
import typing_extensions

from foundry_sdk import _core as core
from foundry_sdk.v1.core import models as core_models
Expand All @@ -30,7 +31,7 @@ class Branch(core.ModelBase):
transaction_rid: typing.Optional[TransactionRid] = pydantic.Field(alias=str("transactionRid"), default=None) # type: ignore[literal-required]


BranchId = str
BranchId: typing_extensions.TypeAlias = str
"""The identifier (name) of a Branch."""


Expand Down Expand Up @@ -62,11 +63,11 @@ class Dataset(core.ModelBase):
parent_folder_rid: core_models.FolderRid = pydantic.Field(alias=str("parentFolderRid")) # type: ignore[literal-required]


DatasetName = str
DatasetName: typing_extensions.TypeAlias = str
"""DatasetName"""


DatasetRid = core.RID
DatasetRid: typing_extensions.TypeAlias = core.RID
"""The Resource Identifier (RID) of a Dataset."""


Expand Down Expand Up @@ -94,7 +95,7 @@ class ListFilesResponse(core.ModelBase):
data: typing.List[File]


TableExportFormat = typing.Literal["ARROW", "CSV"]
TableExportFormat: typing_extensions.TypeAlias = typing.Literal["ARROW", "CSV"]
"""Format for tabular dataset export."""


Expand All @@ -111,15 +112,17 @@ class Transaction(core.ModelBase):
"""The timestamp when the transaction was closed, in ISO 8601 timestamp format."""


TransactionRid = core.RID
TransactionRid: typing_extensions.TypeAlias = core.RID
"""The Resource Identifier (RID) of a Transaction."""


TransactionStatus = typing.Literal["ABORTED", "COMMITTED", "OPEN"]
TransactionStatus: typing_extensions.TypeAlias = typing.Literal["ABORTED", "COMMITTED", "OPEN"]
"""The status of a Transaction."""


TransactionType = typing.Literal["APPEND", "UPDATE", "SNAPSHOT", "DELETE"]
TransactionType: typing_extensions.TypeAlias = typing.Literal[
"APPEND", "UPDATE", "SNAPSHOT", "DELETE"
]
"""The type of a Transaction."""


Expand Down
Loading