88import abc
99from typing import Callable , Dict , Optional
1010
11+ import requests
12+
1113from ..client import Client
1214from ..oauth import Credentials
1315from .external import is_local
1416
15- import requests
16-
1717POSIT_OAUTH_INTEGRATION_AUTH_TYPE = "posit-oauth-integration"
1818POSIT_LOCAL_CLIENT_CREDENTIALS_AUTH_TYPE = "posit-local-client-credentials"
1919
@@ -81,14 +81,15 @@ def _get_auth_type(local_auth_type: str) -> str:
8181
8282 return POSIT_OAUTH_INTEGRATION_AUTH_TYPE
8383
84+
8485class PositLocalContentCredentialsProvider :
8586 """`CredentialsProvider` implementation which provides a fallback for local development using a client credentials flow.
8687
87- There is an open issue against the Databricks CLI which prevents it from returning service principal access tokens.
88+ There is an open issue against the Databricks CLI which prevents it from returning service principal access tokens.
8889 https://github.com/databricks/cli/issues/1939
8990
9091 Until the CLI issue is resolved, this CredentialsProvider implements the approach described in the Databricks documentation
91- for manually generating a workspace-level access token using OAuth M2M authentication. Once it has acquired an access token,
92+ for manually generating a workspace-level access token using OAuth M2M authentication. Once it has acquired an access token,
9293 it returns it as a Bearer authorization header like other `CredentialsProvider` implementations.
9394
9495 See Also
@@ -103,7 +104,7 @@ def __init__(self, token_endpoint_url: str, client_id: str, client_secret: str):
103104
104105 def __call__ (self ) -> Dict [str , str ]:
105106 response = requests .post (
106- self ._token_endpoint_url ,
107+ self ._token_endpoint_url ,
107108 auth = (self ._client_id , self ._client_secret ),
108109 data = {
109110 "grant_type" : "client_credentials" ,
@@ -115,6 +116,7 @@ def __call__(self) -> Dict[str, str]:
115116 credentials = Credentials (** response .json ())
116117 return _new_bearer_authorization_header (credentials )
117118
119+
118120class PositContentCredentialsProvider :
119121 """`CredentialsProvider` implementation which initiates a credential exchange using a content-session-token.
120122
@@ -136,10 +138,10 @@ def __call__(self) -> Dict[str, str]:
136138
137139class PositCredentialsProvider :
138140 """`CredentialsProvider` implementation which initiates a credential exchange using a user-session-token.
139-
140- The user-session-token is provided by Connect through the HTTP session header
141+
142+ The user-session-token is provided by Connect through the HTTP session header
141143 `Posit-Connect-User-Session-Token`.
142-
144+
143145 See Also
144146 --------
145147 * https://github.com/posit-dev/posit-sdk-py/blob/main/src/posit/connect/oauth/oauth.py
@@ -154,47 +156,51 @@ def __call__(self) -> Dict[str, str]:
154156 credentials = self ._client .oauth .get_credentials (self ._user_session_token )
155157 return _new_bearer_authorization_header (credentials )
156158
159+
157160class PositLocalContentCredentialsStrategy (CredentialsStrategy ):
158161 """`CredentialsStrategy` implementation which supports local development using OAuth M2M authentication against Databricks.
159162
160- There is an open issue against the Databricks CLI which prevents it from returning service principal access tokens.
163+ There is an open issue against the Databricks CLI which prevents it from returning service principal access tokens.
161164 https://github.com/databricks/cli/issues/1939
162165
163166 Until the CLI issue is resolved, this CredentialsStrategy provides a drop-in replacement as a local_strategy that can be used
164167 to develop applications which target Service Account OAuth integrations on Connect.
165168
166169 Examples
167170 --------
168- In the example below, the `PositContentCredentialsStrategy` can be initialized anywhere that
171+ In the example below, the `PositContentCredentialsStrategy` can be initialized anywhere that
169172 the Python process can read environment variables.
170173
171174 CLIENT_ID and CLIENT_SECRET are credentials associated with the Databricks service principal.
172175
173176 ```python
174- from posit.connect.external.databricks import PositContentCredentialsStrategy, PositLocalContentCredentialsStrategy
177+ from posit.connect.external.databricks import (
178+ PositContentCredentialsStrategy,
179+ PositLocalContentCredentialsStrategy,
180+ )
175181
176182 import pandas as pd
177183 from databricks import sql
178- from databricks.sdk.core import ApiClient, Config
184+ from databricks.sdk.core import ApiClient, Config
179185 from databricks.sdk.service.iam import CurrentUserAPI
180186
181187 DATABRICKS_HOST = "<REDACTED>"
182188 DATABRICKS_HOST_URL = f"https://{DATABRICKS_HOST}"
183189 SQL_HTTP_PATH = "<REDACTED>"
184190 TOKEN_ENDPOINT_URL = f"https://{DATABRICKS_HOST}/oidc/v1/token"
185191
186- CLIENT_ID = "<REDACTED>"
187- CLIENT_SECRET = "<REDACTED>"
192+ CLIENT_ID = "<REDACTED>"
193+ CLIENT_SECRET = "<REDACTED>"
188194
189- # Rather than relying on the Databricks CLI as a local strategy, we use
195+ # Rather than relying on the Databricks CLI as a local strategy, we use
190196 # PositLocalContentCredentialsStrategy as a drop-in replacement.
191- # Can be replaced with the Databricks CLI implementation when
197+ # Can be replaced with the Databricks CLI implementation when
192198 # https://github.com/databricks/cli/issues/1939 is resolved.
193199 local_strategy = PositLocalContentCredentialsStrategy(
194200 token_endpoint_url=TOKEN_ENDPOINT_URL,
195201 client_id=CLIENT_ID,
196202 client_secret=CLIENT_SECRET,
197- )
203+ )
198204
199205 posit_strategy = PositContentCredentialsStrategy(local_strategy=local_strategy)
200206
@@ -214,27 +220,27 @@ class PositLocalContentCredentialsStrategy(CredentialsStrategy):
214220 rows = cursor.fetchall()
215221 print(pd.DataFrame([row.asDict() for row in rows]))
216222 ```
217-
223+
218224 See Also
219225 --------
220226 * https://docs.databricks.com/en/dev-tools/auth/oauth-m2m.html#manually-generate-a-workspace-level-access-token
221227 """
222228
223229 def __init__ (self , token_endpoint_url : str , client_id : str , client_secret : str ):
224- self ._token_endpoint_url = token_endpoint_url
230+ self ._token_endpoint_url = token_endpoint_url
225231 self ._client_id = client_id
226232 self ._client_secret = client_secret
227233
228- def sql_credentials_provider (self , * args , ** kwargs ):
234+ def sql_credentials_provider (self , * args , ** kwargs ):
229235 return lambda : self .__call__ (* args , ** kwargs )
230236
231237 def auth_type (self ) -> str :
232- return POSIT_LOCAL_CLIENT_CREDENTIALS_AUTH_TYPE
238+ return POSIT_LOCAL_CLIENT_CREDENTIALS_AUTH_TYPE
233239
234- def __call__ (self , * args , ** kwargs ) -> CredentialsProvider :
240+ def __call__ (self , * args , ** kwargs ) -> CredentialsProvider : # noqa: ARG002
235241 return PositLocalContentCredentialsProvider (
236- self ._token_endpoint_url ,
237- self ._client_id ,
242+ self ._token_endpoint_url ,
243+ self ._client_id ,
238244 self ._client_secret ,
239245 )
240246
@@ -247,7 +253,7 @@ class PositContentCredentialsStrategy(CredentialsStrategy):
247253
248254 Examples
249255 --------
250- NOTE: in the example below, the `PositContentCredentialsStrategy` can be initialized anywhere that
256+ NOTE: in the example below, the `PositContentCredentialsStrategy` can be initialized anywhere that
251257 the Python process can read environment variables.
252258
253259 ```python
@@ -265,9 +271,9 @@ class PositContentCredentialsStrategy(CredentialsStrategy):
265271 # NOTE: currently the databricks_cli local strategy only supports auth code OAuth flows.
266272 # https://github.com/databricks/cli/issues/1939
267273 #
268- # This means that the databricks_cli supports local development using the developer's
269- # databricks credentials, but not the credentials for a service principal.
270- # To fallback to service principal credentials in local development, use
274+ # This means that the databricks_cli supports local development using the developer's
275+ # databricks credentials, but not the credentials for a service principal.
276+ # To fallback to service principal credentials in local development, use
271277 # `PositLocalContentCredentialsStrategy` as a drop-in replacement.
272278 posit_strategy = PositContentCredentialsStrategy(local_strategy=databricks_cli)
273279
@@ -331,7 +337,7 @@ class PositCredentialsStrategy(CredentialsStrategy):
331337
332338 Examples
333339 --------
334- NOTE: In the example below, the PositCredentialsProvider *must* be initialized within the context of the
340+ NOTE: In the example below, the PositCredentialsProvider *must* be initialized within the context of the
335341 shiny `server` function, which provides access to the HTTP session headers.
336342
337343 ```python
@@ -343,7 +349,7 @@ class PositCredentialsStrategy(CredentialsStrategy):
343349 from databricks.sdk.service.iam import CurrentUserAPI
344350 from posit.connect.external.databricks import PositCredentialsStrategy
345351 from shiny import App, Inputs, Outputs, Session, render, ui
346-
352+
347353 DATABRICKS_HOST = "<REDACTED>"
348354 DATABRICKS_HOST_URL = f"https://{DATABRICKS_HOST}"
349355 SQL_HTTP_PATH = "<REDACTED>"
@@ -352,7 +358,6 @@ class PositCredentialsStrategy(CredentialsStrategy):
352358
353359
354360 def server(i: Inputs, o: Outputs, session: Session):
355-
356361 # HTTP session headers are available in this context.
357362 session_token = session.http_conn.headers.get("Posit-Connect-User-Session-Token")
358363 posit_strategy = PositCredentialsStrategy(
0 commit comments