databricks-sdk 0.32.2__tar.gz → 0.32.3__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.

Potentially problematic release.


This version of databricks-sdk might be problematic. Click here for more details.

Files changed (91) hide show
  1. {databricks_sdk-0.32.2/databricks_sdk.egg-info → databricks_sdk-0.32.3}/PKG-INFO +1 -1
  2. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/credentials_provider.py +91 -6
  3. databricks_sdk-0.32.3/databricks/sdk/version.py +1 -0
  4. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3/databricks_sdk.egg-info}/PKG-INFO +1 -1
  5. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks_sdk.egg-info/SOURCES.txt +1 -0
  6. databricks_sdk-0.32.3/tests/test_model_serving_auth.py +98 -0
  7. databricks_sdk-0.32.2/databricks/sdk/version.py +0 -1
  8. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/LICENSE +0 -0
  9. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/NOTICE +0 -0
  10. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/README.md +0 -0
  11. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/__init__.py +0 -0
  12. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/__init__.py +0 -0
  13. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/_property.py +0 -0
  14. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/_widgets/__init__.py +0 -0
  15. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/_widgets/default_widgets_utils.py +0 -0
  16. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/_widgets/ipywidgets_utils.py +0 -0
  17. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/azure.py +0 -0
  18. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/casing.py +0 -0
  19. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/clock.py +0 -0
  20. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/config.py +0 -0
  21. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/core.py +0 -0
  22. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/data_plane.py +0 -0
  23. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/dbutils.py +0 -0
  24. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/environments.py +0 -0
  25. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/__init__.py +0 -0
  26. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/base.py +0 -0
  27. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/customizer.py +0 -0
  28. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/deserializer.py +0 -0
  29. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/mapper.py +0 -0
  30. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/overrides.py +0 -0
  31. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/parser.py +0 -0
  32. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/platform.py +0 -0
  33. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/private_link.py +0 -0
  34. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/errors/sdk.py +0 -0
  35. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/logger/__init__.py +0 -0
  36. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/logger/round_trip_logger.py +0 -0
  37. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/mixins/__init__.py +0 -0
  38. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/mixins/compute.py +0 -0
  39. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/mixins/files.py +0 -0
  40. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/mixins/workspace.py +0 -0
  41. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/oauth.py +0 -0
  42. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/py.typed +0 -0
  43. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/retries.py +0 -0
  44. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/runtime/__init__.py +0 -0
  45. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/runtime/dbutils_stub.py +0 -0
  46. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/__init__.py +0 -0
  47. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/_internal.py +0 -0
  48. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/apps.py +0 -0
  49. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/billing.py +0 -0
  50. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/catalog.py +0 -0
  51. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/compute.py +0 -0
  52. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/dashboards.py +0 -0
  53. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/files.py +0 -0
  54. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/iam.py +0 -0
  55. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/jobs.py +0 -0
  56. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/marketplace.py +0 -0
  57. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/ml.py +0 -0
  58. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/oauth2.py +0 -0
  59. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/pipelines.py +0 -0
  60. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/provisioning.py +0 -0
  61. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/serving.py +0 -0
  62. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/settings.py +0 -0
  63. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/sharing.py +0 -0
  64. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/sql.py +0 -0
  65. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/vectorsearch.py +0 -0
  66. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/service/workspace.py +0 -0
  67. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks/sdk/useragent.py +0 -0
  68. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks_sdk.egg-info/dependency_links.txt +0 -0
  69. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks_sdk.egg-info/requires.txt +0 -0
  70. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/databricks_sdk.egg-info/top_level.txt +0 -0
  71. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/setup.cfg +0 -0
  72. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/setup.py +0 -0
  73. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_auth.py +0 -0
  74. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_auth_manual_tests.py +0 -0
  75. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_client.py +0 -0
  76. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_compute_mixins.py +0 -0
  77. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_config.py +0 -0
  78. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_core.py +0 -0
  79. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_data_plane.py +0 -0
  80. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_dbfs_mixins.py +0 -0
  81. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_dbutils.py +0 -0
  82. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_environments.py +0 -0
  83. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_errors.py +0 -0
  84. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_init_file.py +0 -0
  85. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_internal.py +0 -0
  86. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_jobs.py +0 -0
  87. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_metadata_service_auth.py +0 -0
  88. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_misc.py +0 -0
  89. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_oauth.py +0 -0
  90. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_retries.py +0 -0
  91. {databricks_sdk-0.32.2 → databricks_sdk-0.32.3}/tests/test_user_agent.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: databricks-sdk
3
- Version: 0.32.2
3
+ Version: 0.32.3
4
4
  Summary: Databricks SDK for Python (Beta)
5
5
  Home-page: https://databricks-sdk-py.readthedocs.io
6
6
  Author: Serge Smertin
@@ -9,14 +9,15 @@ import pathlib
9
9
  import platform
10
10
  import subprocess
11
11
  import sys
12
+ import time
12
13
  from datetime import datetime
13
- from typing import Callable, Dict, List, Optional, Union
14
+ from typing import Callable, Dict, List, Optional, Tuple, Union
14
15
 
15
- import google.auth
16
+ import google.auth # type: ignore
16
17
  import requests
17
- from google.auth import impersonated_credentials
18
- from google.auth.transport.requests import Request
19
- from google.oauth2 import service_account
18
+ from google.auth import impersonated_credentials # type: ignore
19
+ from google.auth.transport.requests import Request # type: ignore
20
+ from google.oauth2 import service_account # type: ignore
20
21
 
21
22
  from .azure import add_sp_management_token, add_workspace_id_header
22
23
  from .oauth import (ClientCredentials, OAuthClient, Refreshable, Token,
@@ -698,6 +699,90 @@ def metadata_service(cfg: 'Config') -> Optional[CredentialsProvider]:
698
699
  return inner
699
700
 
700
701
 
702
+ # This Code is derived from Mlflow DatabricksModelServingConfigProvider
703
+ # https://github.com/mlflow/mlflow/blob/1219e3ef1aac7d337a618a352cd859b336cf5c81/mlflow/legacy_databricks_cli/configure/provider.py#L332
704
+ class ModelServingAuthProvider():
705
+ _MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH = "/var/credentials-secret/model-dependencies-oauth-token"
706
+
707
+ def __init__(self):
708
+ self.expiry_time = -1
709
+ self.current_token = None
710
+ self.refresh_duration = 300 # 300 Seconds
711
+
712
+ def should_fetch_model_serving_environment_oauth(self) -> bool:
713
+ """
714
+ Check whether this is the model serving environment
715
+ Additionally check if the oauth token file path exists
716
+ """
717
+
718
+ is_in_model_serving_env = (os.environ.get("IS_IN_DB_MODEL_SERVING_ENV")
719
+ or os.environ.get("IS_IN_DATABRICKS_MODEL_SERVING_ENV") or "false")
720
+ return (is_in_model_serving_env == "true"
721
+ and os.path.isfile(self._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH))
722
+
723
+ def get_model_dependency_oauth_token(self, should_retry=True) -> str:
724
+ # Use Cached value if it is valid
725
+ if self.current_token is not None and self.expiry_time > time.time():
726
+ return self.current_token
727
+
728
+ try:
729
+ with open(self._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH) as f:
730
+ oauth_dict = json.load(f)
731
+ self.current_token = oauth_dict["OAUTH_TOKEN"][0]["oauthTokenValue"]
732
+ self.expiry_time = time.time() + self.refresh_duration
733
+ except Exception as e:
734
+ # sleep and retry in case of any race conditions with OAuth refreshing
735
+ if should_retry:
736
+ logger.warning("Unable to read oauth token on first attmept in Model Serving Environment",
737
+ exc_info=e)
738
+ time.sleep(0.5)
739
+ return self.get_model_dependency_oauth_token(should_retry=False)
740
+ else:
741
+ raise RuntimeError(
742
+ "Unable to read OAuth credentials from the file mounted in Databricks Model Serving"
743
+ ) from e
744
+ return self.current_token
745
+
746
+ def get_databricks_host_token(self) -> Optional[Tuple[str, str]]:
747
+ if not self.should_fetch_model_serving_environment_oauth():
748
+ return None
749
+
750
+ # read from DB_MODEL_SERVING_HOST_ENV_VAR if available otherwise MODEL_SERVING_HOST_ENV_VAR
751
+ host = os.environ.get("DATABRICKS_MODEL_SERVING_HOST_URL") or os.environ.get(
752
+ "DB_MODEL_SERVING_HOST_URL")
753
+ token = self.get_model_dependency_oauth_token()
754
+
755
+ return (host, token)
756
+
757
+
758
+ @credentials_strategy('model-serving', [])
759
+ def model_serving_auth(cfg: 'Config') -> Optional[CredentialsProvider]:
760
+ try:
761
+ model_serving_auth_provider = ModelServingAuthProvider()
762
+ if not model_serving_auth_provider.should_fetch_model_serving_environment_oauth():
763
+ logger.debug("model-serving: Not in Databricks Model Serving, skipping")
764
+ return None
765
+ host, token = model_serving_auth_provider.get_databricks_host_token()
766
+ if token is None:
767
+ raise ValueError(
768
+ "Got malformed auth (empty token) when fetching auth implicitly available in Model Serving Environment. Please contact Databricks support"
769
+ )
770
+ if cfg.host is None:
771
+ cfg.host = host
772
+ except Exception as e:
773
+ logger.warning("Unable to get auth from Databricks Model Serving Environment", exc_info=e)
774
+ return None
775
+
776
+ logger.info("Using Databricks Model Serving Authentication")
777
+
778
+ def inner() -> Dict[str, str]:
779
+ # Call here again to get the refreshed token
780
+ _, token = model_serving_auth_provider.get_databricks_host_token()
781
+ return {"Authorization": f"Bearer {token}"}
782
+
783
+ return inner
784
+
785
+
701
786
  class DefaultCredentials:
702
787
  """ Select the first applicable credential provider from the chain """
703
788
 
@@ -706,7 +791,7 @@ class DefaultCredentials:
706
791
  self._auth_providers = [
707
792
  pat_auth, basic_auth, metadata_service, oauth_service_principal, azure_service_principal,
708
793
  github_oidc_azure, azure_cli, external_browser, databricks_cli, runtime_native_auth,
709
- google_credentials, google_id
794
+ google_credentials, google_id, model_serving_auth
710
795
  ]
711
796
 
712
797
  def auth_type(self) -> str:
@@ -0,0 +1 @@
1
+ __version__ = '0.32.3'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: databricks-sdk
3
- Version: 0.32.2
3
+ Version: 0.32.3
4
4
  Summary: Databricks SDK for Python (Beta)
5
5
  Home-page: https://databricks-sdk-py.readthedocs.io
6
6
  Author: Serge Smertin
@@ -83,6 +83,7 @@ tests/test_internal.py
83
83
  tests/test_jobs.py
84
84
  tests/test_metadata_service_auth.py
85
85
  tests/test_misc.py
86
+ tests/test_model_serving_auth.py
86
87
  tests/test_oauth.py
87
88
  tests/test_retries.py
88
89
  tests/test_user_agent.py
@@ -0,0 +1,98 @@
1
+ import time
2
+
3
+ import pytest
4
+
5
+ from databricks.sdk.core import Config
6
+
7
+ from .conftest import raises
8
+
9
+ default_auth_base_error_message = \
10
+ "default auth: cannot configure default credentials, " \
11
+ "please check https://docs.databricks.com/en/dev-tools/auth.html#databricks-client-unified-authentication " \
12
+ "to configure credentials for your preferred authentication method"
13
+
14
+
15
+ @pytest.mark.parametrize(
16
+ "env_values, oauth_file_name",
17
+ [([('IS_IN_DB_MODEL_SERVING_ENV', 'true'),
18
+ ('DB_MODEL_SERVING_HOST_URL', 'x')], "tests/testdata/model-serving-test-token"),
19
+ ([('IS_IN_DATABRICKS_MODEL_SERVING_ENV', 'true'),
20
+ ('DB_MODEL_SERVING_HOST_URL', 'x')], "tests/testdata/model-serving-test-token"),
21
+ ([('IS_IN_DB_MODEL_SERVING_ENV', 'true'),
22
+ ('DATABRICKS_MODEL_SERVING_HOST_URL', 'x')], "tests/testdata/model-serving-test-token"),
23
+ ([('IS_IN_DATABRICKS_MODEL_SERVING_ENV', 'true'),
24
+ ('DATABRICKS_MODEL_SERVING_HOST_URL', 'x')], "tests/testdata/model-serving-test-token"), ])
25
+ def test_model_serving_auth(env_values, oauth_file_name, monkeypatch):
26
+ ## In mlflow we check for these two environment variables to return the correct config
27
+ for (env_name, env_value) in env_values:
28
+ monkeypatch.setenv(env_name, env_value)
29
+ # patch mlflow to read the file from the test directory
30
+ monkeypatch.setattr(
31
+ "databricks.sdk.credentials_provider.ModelServingAuthProvider._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH",
32
+ oauth_file_name)
33
+
34
+ cfg = Config()
35
+
36
+ assert cfg.auth_type == 'model-serving'
37
+ headers = cfg.authenticate()
38
+ assert (cfg.host == 'x')
39
+ # Token defined in the test file
40
+ assert headers.get("Authorization") == 'Bearer databricks_sdk_unit_test_token'
41
+
42
+
43
+ @pytest.mark.parametrize("env_values, oauth_file_name", [
44
+ ([], "invalid_file_name"), # Not in Model Serving and Invalid File Name
45
+ ([('IS_IN_DB_MODEL_SERVING_ENV', 'true')], "invalid_file_name"), # In Model Serving and Invalid File Name
46
+ ([('IS_IN_DATABRICKS_MODEL_SERVING_ENV', 'true')
47
+ ], "invalid_file_name"), # In Model Serving and Invalid File Name
48
+ ([], "tests/testdata/model-serving-test-token") # Not in Model Serving and Valid File Name
49
+ ])
50
+ @raises(default_auth_base_error_message)
51
+ def test_model_serving_auth_errors(env_values, oauth_file_name, monkeypatch):
52
+ for (env_name, env_value) in env_values:
53
+ monkeypatch.setenv(env_name, env_value)
54
+ monkeypatch.setattr(
55
+ "databricks.sdk.credentials_provider.ModelServingAuthProvider._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH",
56
+ oauth_file_name)
57
+
58
+ Config()
59
+
60
+
61
+ def test_model_serving_auth_refresh(monkeypatch):
62
+ ## In mlflow we check for these two environment variables to return the correct config
63
+ monkeypatch.setenv('IS_IN_DB_MODEL_SERVING_ENV', 'true')
64
+ monkeypatch.setenv('DB_MODEL_SERVING_HOST_URL', 'x')
65
+
66
+ # patch mlflow to read the file from the test directory
67
+ monkeypatch.setattr(
68
+ "databricks.sdk.credentials_provider.ModelServingAuthProvider._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH",
69
+ "tests/testdata/model-serving-test-token")
70
+
71
+ cfg = Config()
72
+ assert cfg.auth_type == 'model-serving'
73
+
74
+ current_time = time.time()
75
+ headers = cfg.authenticate()
76
+ assert (cfg.host == 'x')
77
+ assert headers.get(
78
+ "Authorization") == 'Bearer databricks_sdk_unit_test_token' # Token defined in the test file
79
+
80
+ # Simulate refreshing the token by patching to to a new file
81
+ monkeypatch.setattr(
82
+ "databricks.sdk.credentials_provider.ModelServingAuthProvider._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH",
83
+ "tests/testdata/model-serving-test-token-v2")
84
+
85
+ monkeypatch.setattr('databricks.sdk.credentials_provider.time.time', lambda: current_time + 10)
86
+
87
+ headers = cfg.authenticate()
88
+ assert (cfg.host == 'x')
89
+ # Read from cache even though new path is set because expiry is still not hit
90
+ assert headers.get("Authorization") == 'Bearer databricks_sdk_unit_test_token'
91
+
92
+ # Expiry is 300 seconds so this should force an expiry and re read from the new file path
93
+ monkeypatch.setattr('databricks.sdk.credentials_provider.time.time', lambda: current_time + 600)
94
+
95
+ headers = cfg.authenticate()
96
+ assert (cfg.host == 'x')
97
+ # Read V2 now
98
+ assert headers.get("Authorization") == 'Bearer databricks_sdk_unit_test_token_v2'
@@ -1 +0,0 @@
1
- __version__ = '0.32.2'
File without changes
File without changes