Skip to content

Commit e09e4ff

Browse files
authored
feat: release v2.1.21 | Integrate public foundry sdk with fdt authentication (#112)
* add optional public foundry sdk dependency * add public foundry sdk dependency group * add support for creating public sdk clients from existing foundry dev tools context * foundryclient host expects string * add three test cases for new integration * add example for public api -> polars DF * add fakemodule wrapper around foundry_sdk * (fix)add example for public api -> polars DF * add testcase for fakemodule handling * clean up and address PR comments * fix ide autocomplete (https://github.com/emdgroup/foundry-dev-tools/pull/112\#discussion_r2469524144) * simplify examples with real module imports * feat: release v2.1.21
1 parent b09aaaa commit e09e4ff

File tree

10 files changed

+442
-10
lines changed

10 files changed

+442
-10
lines changed

docs/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog],
66
and this project adheres to [Semantic Versioning].
77

8+
## [2.1.21] - 2025-10-28
9+
10+
## Added
11+
- add official foundry-platform-sdk support under FoundryContext for public v2 APIs (#112)
12+
813
## [2.1.20] - 2025-10-24
914

1015
## Added

libs/foundry-dev-tools/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ git-credential-foundry = "foundry_dev_tools.cli.git_credential_foundry:_helper"
4747

4848
[project.optional-dependencies]
4949
s3 = ["aiobotocore[boto3]"]
50-
full = ["foundry-dev-tools-transforms", "foundry-dev-tools[s3]"]
50+
public = ["foundry-platform-sdk"]
51+
full = ["foundry-dev-tools-transforms", "foundry-dev-tools[s3]", "foundry-dev-tools[public]"]
5152

5253
[project.urls]
5354
Homepage = "https://emdgroup.github.io/foundry-dev-tools"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from __future__ import annotations
2+
3+
try:
4+
import foundry_sdk
5+
import foundry_sdk.v2
6+
7+
foundry_sdk.__fake__ = False
8+
except ImportError:
9+
from foundry_dev_tools._optional import FakeModule
10+
11+
foundry_sdk = FakeModule("foundry_sdk")
12+
13+
__all__ = ["foundry_sdk"]

libs/foundry-dev-tools/src/foundry_dev_tools/config/context.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
from foundry_dev_tools.utils.config import entry_point_fdt_api_client
3434

3535
if TYPE_CHECKING:
36+
from foundry_sdk.v2 import FoundryClient as FoundrySdkV2Client
37+
3638
from foundry_dev_tools.cached_foundry_client import CachedFoundryClient
3739
from foundry_dev_tools.config.config_types import Host, Token
3840
from foundry_dev_tools.config.token_provider import TokenProvider
@@ -184,6 +186,29 @@ def foundry_rest_client(self) -> FoundryRestClient:
184186

185187
return FoundryRestClient(ctx=self)
186188

189+
@cached_property
190+
def public_client_v2(self) -> FoundrySdkV2Client:
191+
"""Returns :py:class:`foundry_sdk.v2.FoundryClient`.
192+
193+
Uses fdt context to integrate with the official foundry-platform-sdk.
194+
195+
Examples:
196+
>>> import polars as pl
197+
>>> import pyarrow as pa
198+
199+
>>> pub_client = ctx.public_client_v2
200+
>>> ds = pub_client.datasets.Dataset.read_table(rid, format="ARROW")
201+
>>> pa_df = pa.ipc.open_stream(ds).read_all()
202+
>>> polars_df = pl.from_arrow(pa_df)
203+
"""
204+
from foundry_dev_tools._optional.foundry_platform_sdk import foundry_sdk
205+
from foundry_dev_tools.public_sdk.auth import FoundryDevToolsAuth
206+
207+
return foundry_sdk.v2.FoundryClient(
208+
auth=FoundryDevToolsAuth(self),
209+
hostname=self.host.domain,
210+
)
211+
187212
def get_dataset(
188213
self,
189214
rid: api_types.Rid,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Integration utilities for foundry-platform-sdk."""
2+
3+
from __future__ import annotations
4+
5+
from foundry_dev_tools.public_sdk.auth import FoundryDevToolsAuth, FoundryDevToolsToken
6+
7+
__all__ = [
8+
"FoundryDevToolsAuth",
9+
"FoundryDevToolsToken",
10+
]
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""Auth adapters for integrating FoundryDevTools with foundry-platform-sdk."""
2+
3+
from __future__ import annotations
4+
5+
from abc import ABC, abstractmethod
6+
from typing import TYPE_CHECKING, TypeVar
7+
8+
from foundry_dev_tools._optional.foundry_platform_sdk import foundry_sdk
9+
10+
if TYPE_CHECKING:
11+
from collections.abc import Callable
12+
13+
from foundry_dev_tools.config.context import FoundryContext
14+
15+
16+
class Token(ABC):
17+
"""Reimplementation of the private foundry_sdk Token interface."""
18+
19+
@property
20+
@abstractmethod
21+
def access_token(self) -> str: # noqa: D102
22+
pass
23+
24+
25+
T = TypeVar("T")
26+
27+
28+
class FoundryDevToolsToken(Token):
29+
"""Token adapter that implements the foundry_sdk Token interface."""
30+
31+
def __init__(self, token: str) -> None:
32+
"""Initialize the token wrapper.
33+
34+
Args:
35+
token (str): The access token string
36+
"""
37+
self._token = token
38+
39+
@property
40+
def access_token(self) -> str:
41+
"""Return the access token.
42+
43+
Returns:
44+
str: The access token
45+
"""
46+
return self._token
47+
48+
49+
class FoundryDevToolsAuth(foundry_sdk.Auth):
50+
"""Auth adapter that bridges FoundryContext with foundry-platform-sdk."""
51+
52+
def __init__(self, ctx: FoundryContext) -> None:
53+
"""Initialize the auth adapter.
54+
55+
Args:
56+
ctx: The FoundryContext instance to use for authentication
57+
"""
58+
self._ctx: FoundryContext = ctx
59+
60+
def get_token(self) -> FoundryDevToolsToken:
61+
"""Get the current token from the FoundryContext.
62+
63+
Returns:
64+
FoundryDevToolsToken: The wrapped access token
65+
"""
66+
return FoundryDevToolsToken(self._ctx.token)
67+
68+
def execute_with_token(self, func: Callable[[FoundryDevToolsToken], T]) -> T:
69+
"""Execute a function with the current token.
70+
71+
Args:
72+
func: Function to execute with the token
73+
74+
Returns:
75+
T: The return value of the function
76+
"""
77+
return func(self.get_token())
78+
79+
def run_with_token(self, func: Callable[[FoundryDevToolsToken], T]) -> None:
80+
"""Run a function with the current token without returning a value.
81+
82+
Args:
83+
func: Function to run with the token
84+
"""
85+
func(self.get_token())

0 commit comments

Comments
 (0)