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
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,35 @@ with open("result.png", "wb") as f:

<a id="static-types"></a>
## Static type analysis

### Hashable Models

All model objects in the SDK can be used as dictionary keys or set members. This provides several benefits:

```python
# Example: Using models as dictionary keys
from foundry_sdk import FoundryClient

client = FoundryClient(...)
file1 = client.datasets.Dataset.File.get(dataset_rid="ri.foundry.main.dataset.123", file_path="/data.csv")
file2 = client.datasets.Dataset.File.get(dataset_rid="ri.foundry.main.dataset.123", file_path="/data.csv")

# Models with the same content are equal and have the same hash
assert file1 == file2
assert hash(file1) == hash(file2)

# Use models as dictionary keys
file_metadata = {}
file_metadata[file1] = {"last_modified": "2024-08-09"}

# Can look up using any equivalent object
assert file_metadata[file2] == {"last_modified": "2024-08-09"}
```

**Note:** Models remain mutable for backward compatibility. If you modify a model after using it as a dictionary key,
the system will issue a warning and the model's hash value will be reset. Although allowed, mutating models and using
their hash values is not recommended as it can lead to unexpected behavior when using them in dictionaries or sets.

This library uses [Pydantic](https://docs.pydantic.dev) for creating and validating data models which you will see in the
method definitions (see [Documentation for Models](#models-link) below for a full list of models).
All request parameters and responses with nested fields are typed using a Pydantic
Expand Down Expand Up @@ -1255,10 +1284,13 @@ Namespace | Name | Import |
**Filesystem** | [SpaceRid](docs/v2/Filesystem/models/SpaceRid.md) | `from foundry_sdk.v2.filesystem.models import SpaceRid` |
**Filesystem** | [TrashStatus](docs/v2/Filesystem/models/TrashStatus.md) | `from foundry_sdk.v2.filesystem.models import TrashStatus` |
**Filesystem** | [UsageAccountRid](docs/v2/Filesystem/models/UsageAccountRid.md) | `from foundry_sdk.v2.filesystem.models import UsageAccountRid` |
**Functions** | [ArrayConstraint](docs/v2/Functions/models/ArrayConstraint.md) | `from foundry_sdk.v2.functions.models import ArrayConstraint` |
**Functions** | [DataValue](docs/v2/Functions/models/DataValue.md) | `from foundry_sdk.v2.functions.models import DataValue` |
**Functions** | [EnumConstraint](docs/v2/Functions/models/EnumConstraint.md) | `from foundry_sdk.v2.functions.models import EnumConstraint` |
**Functions** | [ExecuteQueryResponse](docs/v2/Functions/models/ExecuteQueryResponse.md) | `from foundry_sdk.v2.functions.models import ExecuteQueryResponse` |
**Functions** | [FunctionRid](docs/v2/Functions/models/FunctionRid.md) | `from foundry_sdk.v2.functions.models import FunctionRid` |
**Functions** | [FunctionVersion](docs/v2/Functions/models/FunctionVersion.md) | `from foundry_sdk.v2.functions.models import FunctionVersion` |
**Functions** | [LengthConstraint](docs/v2/Functions/models/LengthConstraint.md) | `from foundry_sdk.v2.functions.models import LengthConstraint` |
**Functions** | [Parameter](docs/v2/Functions/models/Parameter.md) | `from foundry_sdk.v2.functions.models import Parameter` |
**Functions** | [ParameterId](docs/v2/Functions/models/ParameterId.md) | `from foundry_sdk.v2.functions.models import ParameterId` |
**Functions** | [Query](docs/v2/Functions/models/Query.md) | `from foundry_sdk.v2.functions.models import Query` |
Expand All @@ -1274,11 +1306,18 @@ Namespace | Name | Import |
**Functions** | [QueryStructField](docs/v2/Functions/models/QueryStructField.md) | `from foundry_sdk.v2.functions.models import QueryStructField` |
**Functions** | [QueryStructType](docs/v2/Functions/models/QueryStructType.md) | `from foundry_sdk.v2.functions.models import QueryStructType` |
**Functions** | [QueryUnionType](docs/v2/Functions/models/QueryUnionType.md) | `from foundry_sdk.v2.functions.models import QueryUnionType` |
**Functions** | [RangesConstraint](docs/v2/Functions/models/RangesConstraint.md) | `from foundry_sdk.v2.functions.models import RangesConstraint` |
**Functions** | [RegexConstraint](docs/v2/Functions/models/RegexConstraint.md) | `from foundry_sdk.v2.functions.models import RegexConstraint` |
**Functions** | [RidConstraint](docs/v2/Functions/models/RidConstraint.md) | `from foundry_sdk.v2.functions.models import RidConstraint` |
**Functions** | [StructConstraint](docs/v2/Functions/models/StructConstraint.md) | `from foundry_sdk.v2.functions.models import StructConstraint` |
**Functions** | [StructFieldApiName](docs/v2/Functions/models/StructFieldApiName.md) | `from foundry_sdk.v2.functions.models import StructFieldApiName` |
**Functions** | [StructFieldName](docs/v2/Functions/models/StructFieldName.md) | `from foundry_sdk.v2.functions.models import StructFieldName` |
**Functions** | [ThreeDimensionalAggregation](docs/v2/Functions/models/ThreeDimensionalAggregation.md) | `from foundry_sdk.v2.functions.models import ThreeDimensionalAggregation` |
**Functions** | [TwoDimensionalAggregation](docs/v2/Functions/models/TwoDimensionalAggregation.md) | `from foundry_sdk.v2.functions.models import TwoDimensionalAggregation` |
**Functions** | [UuidConstraint](docs/v2/Functions/models/UuidConstraint.md) | `from foundry_sdk.v2.functions.models import UuidConstraint` |
**Functions** | [ValueType](docs/v2/Functions/models/ValueType.md) | `from foundry_sdk.v2.functions.models import ValueType` |
**Functions** | [ValueTypeApiName](docs/v2/Functions/models/ValueTypeApiName.md) | `from foundry_sdk.v2.functions.models import ValueTypeApiName` |
**Functions** | [ValueTypeConstraint](docs/v2/Functions/models/ValueTypeConstraint.md) | `from foundry_sdk.v2.functions.models import ValueTypeConstraint` |
**Functions** | [ValueTypeDataType](docs/v2/Functions/models/ValueTypeDataType.md) | `from foundry_sdk.v2.functions.models import ValueTypeDataType` |
**Functions** | [ValueTypeDataTypeArrayType](docs/v2/Functions/models/ValueTypeDataTypeArrayType.md) | `from foundry_sdk.v2.functions.models import ValueTypeDataTypeArrayType` |
**Functions** | [ValueTypeDataTypeBinaryType](docs/v2/Functions/models/ValueTypeDataTypeBinaryType.md) | `from foundry_sdk.v2.functions.models import ValueTypeDataTypeBinaryType` |
Expand Down Expand Up @@ -2389,6 +2428,7 @@ Namespace | Name | Import |
**Ontologies** | PropertyBaseTypeNotSupported | `from foundry_sdk.v2.ontologies.errors import PropertyBaseTypeNotSupported` |
**Ontologies** | PropertyFiltersNotSupported | `from foundry_sdk.v2.ontologies.errors import PropertyFiltersNotSupported` |
**Ontologies** | PropertyNotFound | `from foundry_sdk.v2.ontologies.errors import PropertyNotFound` |
**Ontologies** | PropertyNotFoundOnObject | `from foundry_sdk.v2.ontologies.errors import PropertyNotFoundOnObject` |
**Ontologies** | PropertyTypeDoesNotSupportNearestNeighbors | `from foundry_sdk.v2.ontologies.errors import PropertyTypeDoesNotSupportNearestNeighbors` |
**Ontologies** | PropertyTypeNotFound | `from foundry_sdk.v2.ontologies.errors import PropertyTypeNotFound` |
**Ontologies** | PropertyTypeRidNotFound | `from foundry_sdk.v2.ontologies.errors import PropertyTypeRidNotFound` |
Expand Down Expand Up @@ -2623,6 +2663,7 @@ Namespace | Name | Import |
**Ontologies** | PropertyBaseTypeNotSupported | `from foundry_sdk.v1.ontologies.errors import PropertyBaseTypeNotSupported` |
**Ontologies** | PropertyFiltersNotSupported | `from foundry_sdk.v1.ontologies.errors import PropertyFiltersNotSupported` |
**Ontologies** | PropertyNotFound | `from foundry_sdk.v1.ontologies.errors import PropertyNotFound` |
**Ontologies** | PropertyNotFoundOnObject | `from foundry_sdk.v1.ontologies.errors import PropertyNotFoundOnObject` |
**Ontologies** | PropertyTypeDoesNotSupportNearestNeighbors | `from foundry_sdk.v1.ontologies.errors import PropertyTypeDoesNotSupportNearestNeighbors` |
**Ontologies** | PropertyTypeNotFound | `from foundry_sdk.v1.ontologies.errors import PropertyTypeNotFound` |
**Ontologies** | PropertyTypeRidNotFound | `from foundry_sdk.v1.ontologies.errors import PropertyTypeRidNotFound` |
Expand Down
2 changes: 1 addition & 1 deletion docs-snippets-npm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"sls": {
"dependencies": {
"com.palantir.foundry.api:api-gateway": {
"minVersion": "1.1254.0",
"minVersion": "1.1261.0",
"maxVersion": "1.x.x",
"optional": false
}
Expand Down
15 changes: 15 additions & 0 deletions docs/v2/Functions/models/ArrayConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ArrayConstraint

ArrayConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**minimum_size** | Optional[int] | No | |
**maximum_size** | Optional[int] | No | |
**unique_values** | bool | Yes | |
**value_constraint** | Optional[ValueTypeConstraint] | No | |
**type** | Literal["array"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
12 changes: 12 additions & 0 deletions docs/v2/Functions/models/EnumConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# EnumConstraint

EnumConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**options** | List[Any] | Yes | |
**type** | Literal["enum"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
13 changes: 13 additions & 0 deletions docs/v2/Functions/models/LengthConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# LengthConstraint

LengthConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**minimum_length** | Optional[int] | No | |
**maximum_length** | Optional[int] | No | |
**type** | Literal["length"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
13 changes: 13 additions & 0 deletions docs/v2/Functions/models/RangesConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# RangesConstraint

RangesConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**minimum_value** | Optional[Any] | No | |
**maximum_value** | Optional[Any] | No | |
**type** | Literal["range"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
13 changes: 13 additions & 0 deletions docs/v2/Functions/models/RegexConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# RegexConstraint

RegexConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**pattern** | str | Yes | |
**partial_match** | bool | Yes | |
**type** | Literal["regex"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
11 changes: 11 additions & 0 deletions docs/v2/Functions/models/RidConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# RidConstraint

RidConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**type** | Literal["rid"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
12 changes: 12 additions & 0 deletions docs/v2/Functions/models/StructConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# StructConstraint

StructConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**fields** | Dict[StructFieldApiName, ValueTypeApiName] | Yes | |
**type** | Literal["struct"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
11 changes: 11 additions & 0 deletions docs/v2/Functions/models/StructFieldApiName.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# StructFieldApiName

StructFieldApiName

## Type
```python
str
```


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
11 changes: 11 additions & 0 deletions docs/v2/Functions/models/UuidConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# UuidConstraint

UuidConstraint

## Properties
| Name | Type | Required | Description |
| ------------ | ------------- | ------------- | ------------- |
**type** | Literal["uuid"] | Yes | None |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
1 change: 1 addition & 0 deletions docs/v2/Functions/models/ValueType.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ValueType
**display_name** | DisplayName | Yes | |
**description** | Optional[ValueTypeDescription] | No | |
**base_type** | Optional[ValueTypeDataType] | No | |
**constraints** | List[ValueTypeConstraint] | Yes | |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
22 changes: 22 additions & 0 deletions docs/v2/Functions/models/ValueTypeConstraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ValueTypeConstraint

ValueTypeConstraint

This is a discriminator type and does not contain any fields. Instead, it is a union
of of the models listed below.

This discriminator class uses the `type` field to differentiate between classes.

| Class | Value
| ------------ | -------------
StructConstraint | struct
RegexConstraint | regex
ArrayConstraint | array
LengthConstraint | length
RangesConstraint | range
RidConstraint | rid
UuidConstraint | uuid
EnumConstraint | enum


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
1 change: 1 addition & 0 deletions docs/v2/Functions/models/VersionId.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ VersionId
**display_name** | DisplayName | Yes | |
**description** | Optional[ValueTypeDescription] | No | |
**base_type** | Optional[ValueTypeDataType] | No | |
**constraints** | List[ValueTypeConstraint] | Yes | |


[[Back to Model list]](../../../../README.md#models-v2-link) [[Back to API list]](../../../../README.md#apis-v2-link) [[Back to README]](../../../../README.md)
1 change: 1 addition & 0 deletions foundry_sdk/_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from foundry_sdk._core.compute_module_pipeline_auth import ComputeModulePipelineAuth
from foundry_sdk._core.confidential_client_auth import ConfidentialClientAuth
from foundry_sdk._core.config import Config
from foundry_sdk._core.model_base import ModelBase
from foundry_sdk._core.public_client_auth import PublicClientAuth
from foundry_sdk._core.resource_iterator import AsyncResourceIterator
from foundry_sdk._core.resource_iterator import ResourceIterator
Expand Down
2 changes: 1 addition & 1 deletion foundry_sdk/_core/confidential_client_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def get_token(self) -> OAuthToken:

return self._token

def revoke_token(self) -> None:
def _revoke_token(self) -> None:
if self._token:
self._server_oauth_flow_provider.revoke_token(
self._get_client(),
Expand Down
98 changes: 98 additions & 0 deletions foundry_sdk/_core/model_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Copyright 2024 Palantir Technologies, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import json
import warnings
from typing import Any
from typing import Dict
from typing import Hashable
from typing import Optional
from typing import cast

import pydantic


class ModelBase(pydantic.BaseModel):
"""
Base class for all model objects in the SDK.

This base model supports being used as a dictionary key while preserving mutability.
It tracks if it has been used as a hash key and warns if mutation occurs after hashing.
"""

model_config = {"extra": "allow", "populate_by_name": True}

def __init__(self, **data):
super().__init__(**data)
self._hash_called = False
self._hash_value: Optional[int] = None

def __hash__(self) -> int:
"""
Generate a hash based on class identity and attribute values.
"""
if self._hash_value is None:
self._hash_called = True

def make_hashable(value: Any) -> Hashable:
if isinstance(value, dict):
return tuple((k, make_hashable(v)) for k, v in sorted(value.items()))
elif isinstance(value, (list, set)):
return tuple(make_hashable(v) for v in value)
else:
return value

# Include class type in the hash
class_identifier = self.__class__.__name__

# Create hashable representations of all fields
hash_fields = tuple(
(field, make_hashable(getattr(self, field))) for field in self.model_fields
)

# Hash combination of class identifier and field values
self._hash_value = hash((class_identifier, hash_fields))

return self._hash_value

def __setattr__(self, name: str, value: Any) -> None:
"""
Track attribute mutations and warn if the model has been hashed.

Once a model has been used as a dictionary key, modifying it could cause
unexpected behavior, as the dictionary location is determined by the hash
value at insertion time.
"""
# Check if we're setting special attributes used by this class
if name in ("_hash_called", "_hash_value"):
super().__setattr__(name, value)
return

# If hash has been called, warn about the mutation and reset the hash
if self._hash_called:
warnings.warn(
f"Modifying {self.__class__.__name__} after it has been used as a dictionary key "
"may lead to unexpected behavior.",
UserWarning,
stacklevel=2,
)
# Reset the hash value since the object has changed
self._hash_value = None

super().__setattr__(name, value)

def to_dict(self) -> Dict[str, Any]:
"""Return the dictionary representation of the model using the field aliases."""
return cast(Dict[str, Any], self.model_dump(by_alias=True, exclude_none=True))
5 changes: 3 additions & 2 deletions foundry_sdk/_core/oauth_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def __init__(
self._token: Optional[OAuthToken] = None

def sign_out(self) -> SignOutResponse:
self.revoke_token()
self._revoke_token()
self._token = None
# Signal the auto-refresh thread to stop
self._stop_refresh_event.set()
Expand All @@ -164,7 +164,7 @@ def get_token(self) -> OAuthToken:
pass

@abstractmethod
def revoke_token(self) -> None:
def _revoke_token(self) -> None:
pass

@abstractmethod
Expand Down Expand Up @@ -193,6 +193,7 @@ def _run_with_attempted_refresh(self, func: Callable[[OAuthToken], T]) -> T:
except httpx.HTTPStatusError as e:
if e.response.status_code == 401:
if not self._try_refresh_token():
warnings.warn("OAuth token refresh failed", UserWarning, stacklevel=2)
raise e
return func(self.get_token())
else:
Expand Down
Loading