py2docfx 0.1.21.dev2253172__py3-none-any.whl → 0.1.22__py3-none-any.whl

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.
Files changed (49) hide show
  1. py2docfx/docfx_yaml/process_doctree.py +3 -23
  2. py2docfx/docfx_yaml/translator.py +6 -35
  3. py2docfx/docfx_yaml/type_mapping.py +102 -0
  4. py2docfx/venv/basevenv/Lib/site-packages/certifi/__init__.py +1 -1
  5. py2docfx/venv/basevenv/Lib/site-packages/markupsafe/__init__.py +3 -2
  6. py2docfx/venv/basevenv/Lib/site-packages/yaml/__init__.py +1 -1
  7. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +8 -9
  8. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +7 -3
  9. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/managed_identity.py +7 -1
  10. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/shared_cache.py +2 -2
  11. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +2 -2
  12. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_managed_identity_client.py +1 -1
  13. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
  14. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +8 -9
  15. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +7 -3
  16. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/managed_identity.py +7 -1
  17. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/shared_cache.py +2 -2
  18. py2docfx/venv/venv1/Lib/site-packages/cachetools/__init__.py +96 -122
  19. py2docfx/venv/venv1/Lib/site-packages/cachetools/{_decorators.py → _cached.py} +106 -13
  20. py2docfx/venv/venv1/Lib/site-packages/cachetools/_cachedmethod.py +128 -0
  21. py2docfx/venv/venv1/Lib/site-packages/cachetools/func.py +5 -25
  22. py2docfx/venv/venv1/Lib/site-packages/certifi/__init__.py +1 -1
  23. py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
  24. py2docfx/venv/venv1/Lib/site-packages/google/api_core/client_options.py +9 -2
  25. py2docfx/venv/venv1/Lib/site-packages/google/api_core/general_helpers.py +36 -0
  26. py2docfx/venv/venv1/Lib/site-packages/google/api_core/grpc_helpers.py +10 -7
  27. py2docfx/venv/venv1/Lib/site-packages/google/api_core/grpc_helpers_async.py +8 -3
  28. py2docfx/venv/venv1/Lib/site-packages/google/api_core/operations_v1/transports/base.py +13 -7
  29. py2docfx/venv/venv1/Lib/site-packages/google/api_core/operations_v1/transports/rest.py +19 -12
  30. py2docfx/venv/venv1/Lib/site-packages/google/api_core/operations_v1/transports/rest_asyncio.py +21 -0
  31. py2docfx/venv/venv1/Lib/site-packages/google/api_core/version.py +1 -1
  32. py2docfx/venv/venv1/Lib/site-packages/google/auth/_default.py +66 -12
  33. py2docfx/venv/venv1/Lib/site-packages/google/auth/_default_async.py +16 -10
  34. py2docfx/venv/venv1/Lib/site-packages/google/auth/_helpers.py +41 -0
  35. py2docfx/venv/venv1/Lib/site-packages/google/auth/compute_engine/credentials.py +67 -6
  36. py2docfx/venv/venv1/Lib/site-packages/google/auth/credentials.py +161 -18
  37. py2docfx/venv/venv1/Lib/site-packages/google/auth/environment_vars.py +4 -0
  38. py2docfx/venv/venv1/Lib/site-packages/google/auth/external_account.py +33 -10
  39. py2docfx/venv/venv1/Lib/site-packages/google/auth/external_account_authorized_user.py +24 -1
  40. py2docfx/venv/venv1/Lib/site-packages/google/auth/identity_pool.py +25 -1
  41. py2docfx/venv/venv1/Lib/site-packages/google/auth/impersonated_credentials.py +57 -9
  42. py2docfx/venv/venv1/Lib/site-packages/google/auth/pluggable.py +25 -1
  43. py2docfx/venv/venv1/Lib/site-packages/google/auth/version.py +1 -1
  44. py2docfx/venv/venv1/Lib/site-packages/google/oauth2/_client.py +117 -0
  45. py2docfx/venv/venv1/Lib/site-packages/google/oauth2/service_account.py +39 -4
  46. {py2docfx-0.1.21.dev2253172.dist-info → py2docfx-0.1.22.dist-info}/METADATA +1 -1
  47. {py2docfx-0.1.21.dev2253172.dist-info → py2docfx-0.1.22.dist-info}/RECORD +49 -47
  48. {py2docfx-0.1.21.dev2253172.dist-info → py2docfx-0.1.22.dist-info}/WHEEL +0 -0
  49. {py2docfx-0.1.21.dev2253172.dist-info → py2docfx-0.1.22.dist-info}/top_level.txt +0 -0
@@ -12,28 +12,13 @@ from utils import transform_string
12
12
  from enum import EnumMeta
13
13
  from importlib import import_module
14
14
  from logger import get_package_logger
15
+ from type_mapping import map_type_transformations, PACKAGE, METHOD, FUNCTION, DATA, MODULE, CLASS, EXCEPTION, ATTRIBUTE, PROPERTY, PYDANTIC_MODEL, PYDANTIC_FIELD, PYDANTIC_SETTINGS, PYDANTIC_VALIDATOR, PYDANTIC_CONFIG
15
16
 
16
- PACKAGE = 'package'
17
- METHOD = 'method'
18
- FUNCTION = 'function'
19
- DATA = 'data'
20
- MODULE = 'module'
21
- CLASS = 'class'
22
- EXCEPTION = 'exception'
23
- ATTRIBUTE = 'attribute'
24
- PROPERTY = 'property'
25
17
  REFMETHOD = 'meth'
26
18
  REFFUNCTION = 'func'
27
19
  REF_PATTERN = ':(py:)?(func|class|meth|mod|ref):`~?[a-zA-Z_\.<> ]*?`'
28
20
  INITPY = '__init__.py'
29
21
 
30
- #Pydantic specific types
31
- PYDANTIC_MODEL = 'pydantic_model'
32
- PYDANTIC_FIELD = 'pydantic_field'
33
- PYDANTIC_SETTINGS = 'pydantic_settings'
34
- PYDANTIC_VALIDATOR = 'pydantic_validator'
35
- PYDANTIC_CONFIG = 'pydantic_config'
36
-
37
22
  def _fullname(obj):
38
23
  """
39
24
  Get the fullname from a Python object
@@ -395,13 +380,8 @@ def process_docstring(app, _type, name, obj, options, lines):
395
380
  return PACKAGE
396
381
  return _type
397
382
 
398
- # Type transformations
399
- if _type == EXCEPTION or _type in {PYDANTIC_MODEL, PYDANTIC_SETTINGS, PYDANTIC_CONFIG}:
400
- _type = CLASS
401
- elif _type == PROPERTY or _type == PYDANTIC_FIELD:
402
- _type = ATTRIBUTE
403
- elif _type == PYDANTIC_VALIDATOR:
404
- _type = METHOD
383
+ # Apply type transformations using shared mapping function
384
+ _type = map_type_transformations(_type)
405
385
 
406
386
  _type = check_convert_package_type(obj, _type)
407
387
  cls, module = _get_cls_module(_type, name)
@@ -15,35 +15,15 @@ from sphinx.util.docfields import _is_single_paragraph
15
15
  from collections import OrderedDict
16
16
  from nodes import remarks
17
17
  from logger import get_package_logger
18
+ from type_mapping import (
19
+ translator_type_mapping, CLASS_TYPE, EXCEPTION_TYPE, ATTRIBUTE_TYPE,
20
+ PYDANTIC_MODEL_TYPE, PYDANTIC_SETTINGS_TYPE, PYDANTIC_FIELD_TYPE, PYDANTIC_CONFIG_TYPE,
21
+ types_contain_constructor, types_contain_attributes, attribute_types
22
+ )
18
23
 
19
24
  TYPE_SEP_PATTERN = '(\[|\]|, |\(|\))'
20
25
  PARAMETER_NAME = "[*][*](.*?)[*][*]"
21
26
  PARAMETER_TYPE = "[(]((?:.|\n)*)[)]"
22
- CLASS_TYPE = 'class'
23
- EXCEPTION_TYPE = 'exception'
24
- ATTRIBUTE_TYPE = 'attribute'
25
-
26
- # Pydantic specific types
27
- PYDANTIC_MODEL_TYPE = "pydantic_model"
28
- PYDANTIC_SETTINGS_TYPE = "pydantic_settings"
29
- PYDANTIC_FIELD_TYPE = "pydantic_field"
30
- PYDANTIC_CONFIG_TYPE = "pydantic_config"
31
-
32
- types_contain_constructor = {
33
- CLASS_TYPE,
34
- PYDANTIC_MODEL_TYPE,
35
- PYDANTIC_SETTINGS_TYPE,
36
- EXCEPTION_TYPE,
37
- PYDANTIC_CONFIG_TYPE,
38
- }
39
- types_contain_attributes = {
40
- CLASS_TYPE,
41
- PYDANTIC_MODEL_TYPE,
42
- PYDANTIC_SETTINGS_TYPE,
43
- EXCEPTION_TYPE,
44
- PYDANTIC_CONFIG_TYPE,
45
- }
46
- attribute_types = {PYDANTIC_FIELD_TYPE, ATTRIBUTE_TYPE}
47
27
 
48
28
  def translator(app, docname, doctree):
49
29
 
@@ -64,15 +44,6 @@ def translator(app, docname, doctree):
64
44
  else:
65
45
  return para_field.astext()
66
46
 
67
- def type_mapping(type_name):
68
- mapping = {
69
- "staticmethod": "method",
70
- "classmethod": "method",
71
- "exception": "class",
72
- }
73
-
74
- return mapping[type_name] if type_name in mapping else type_name
75
-
76
47
  def _get_uid_and_type_from_desc(node):
77
48
  assert node.tagname == 'desc'
78
49
  if node.attributes['domain'] != 'py':
@@ -493,7 +464,7 @@ def translator(app, docname, doctree):
493
464
  data.update(extract_content(content_child, node_type, module_name))
494
465
  data['content'] = extract_signature(signature_child)
495
466
 
496
- data['type'] = type_mapping(node_type) if node_type else 'unknown'
467
+ data['type'] = translator_type_mapping(node_type) if node_type else 'unknown'
497
468
  if _is_property_node(signature_child):
498
469
  data['type'] = ATTRIBUTE_TYPE
499
470
 
@@ -0,0 +1,102 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # ---------------------------------------------------------
4
+ # Copyright (c) Microsoft Corporation. All rights reserved.
5
+ # ---------------------------------------------------------
6
+
7
+ """
8
+ Type mapping utilities for converting various documentation types to standardized forms.
9
+ """
10
+
11
+ # Standard types
12
+ PACKAGE = 'package'
13
+ METHOD = 'method'
14
+ FUNCTION = 'function'
15
+ DATA = 'data'
16
+ MODULE = 'module'
17
+ CLASS = 'class'
18
+ EXCEPTION = 'exception'
19
+ ATTRIBUTE = 'attribute'
20
+ PROPERTY = 'property'
21
+
22
+ # Pydantic specific types
23
+ PYDANTIC_MODEL = 'pydantic_model'
24
+ PYDANTIC_FIELD = 'pydantic_field'
25
+ PYDANTIC_SETTINGS = 'pydantic_settings'
26
+ PYDANTIC_VALIDATOR = 'pydantic_validator'
27
+ PYDANTIC_CONFIG = 'pydantic_config'
28
+
29
+ # Translator-style constants (for compatibility)
30
+ CLASS_TYPE = 'class'
31
+ EXCEPTION_TYPE = 'exception'
32
+ ATTRIBUTE_TYPE = 'attribute'
33
+ PYDANTIC_MODEL_TYPE = "pydantic_model"
34
+ PYDANTIC_SETTINGS_TYPE = "pydantic_settings"
35
+ PYDANTIC_FIELD_TYPE = "pydantic_field"
36
+ PYDANTIC_CONFIG_TYPE = "pydantic_config"
37
+
38
+ # Type groupings for translator functionality
39
+ types_contain_constructor = {
40
+ CLASS_TYPE,
41
+ PYDANTIC_MODEL_TYPE,
42
+ PYDANTIC_SETTINGS_TYPE,
43
+ EXCEPTION_TYPE,
44
+ PYDANTIC_CONFIG_TYPE,
45
+ }
46
+
47
+ types_contain_attributes = {
48
+ CLASS_TYPE,
49
+ PYDANTIC_MODEL_TYPE,
50
+ PYDANTIC_SETTINGS_TYPE,
51
+ EXCEPTION_TYPE,
52
+ PYDANTIC_CONFIG_TYPE,
53
+ }
54
+
55
+ attribute_types = {PYDANTIC_FIELD_TYPE, ATTRIBUTE_TYPE}
56
+
57
+
58
+ def map_type_transformations(type_name):
59
+ """
60
+ Apply type transformations to convert various documentation types to standardized forms.
61
+ Used by process_doctree.py for initial type processing.
62
+
63
+ Args:
64
+ type_name (str): The original type name
65
+
66
+ Returns:
67
+ str: The transformed type name
68
+ """
69
+ # Type transformations
70
+ if type_name == EXCEPTION or type_name in {PYDANTIC_MODEL, PYDANTIC_SETTINGS, PYDANTIC_CONFIG}:
71
+ return CLASS
72
+ elif type_name == PROPERTY or type_name == PYDANTIC_FIELD:
73
+ return ATTRIBUTE
74
+ elif type_name == PYDANTIC_VALIDATOR:
75
+ return METHOD
76
+
77
+ # Return original type if no transformation needed
78
+ return type_name
79
+
80
+
81
+ def translator_type_mapping(type_name):
82
+ """
83
+ Apply type mapping transformations for translator processing.
84
+ Used by translator.py for docstring processing.
85
+ Includes both original translator mappings and process_doctree transformations.
86
+
87
+ Args:
88
+ type_name (str): The original type name
89
+
90
+ Returns:
91
+ str: The mapped type name
92
+ """
93
+ # First apply the process_doctree style transformations
94
+ transformed_type = map_type_transformations(type_name)
95
+
96
+ # Then apply the original translator mappings
97
+ mapping = {
98
+ "staticmethod": "method",
99
+ "classmethod": "method",
100
+ }
101
+
102
+ return mapping[transformed_type] if transformed_type in mapping else transformed_type
@@ -1,4 +1,4 @@
1
1
  from .core import contents, where
2
2
 
3
3
  __all__ = ["contents", "where"]
4
- __version__ = "2025.08.03"
4
+ __version__ = "2025.10.05"
@@ -214,14 +214,14 @@ class Markup(str):
214
214
  if (end := value.find("-->", start)) == -1:
215
215
  break
216
216
 
217
- value = f"{value[:start]}{value[end + 3:]}"
217
+ value = f"{value[:start]}{value[end + 3 :]}"
218
218
 
219
219
  # remove tags using the same method
220
220
  while (start := value.find("<")) != -1:
221
221
  if (end := value.find(">", start)) == -1:
222
222
  break
223
223
 
224
- value = f"{value[:start]}{value[end + 1:]}"
224
+ value = f"{value[:start]}{value[end + 1 :]}"
225
225
 
226
226
  # collapse spaces
227
227
  value = " ".join(value.split())
@@ -388,6 +388,7 @@ def __getattr__(name: str) -> t.Any:
388
388
  "The '__version__' attribute is deprecated and will be removed in"
389
389
  " MarkupSafe 3.1. Use feature detection, or"
390
390
  ' `importlib.metadata.version("markupsafe")`, instead.',
391
+ DeprecationWarning,
391
392
  stacklevel=2,
392
393
  )
393
394
  return importlib.metadata.version("markupsafe")
@@ -8,7 +8,7 @@ from .nodes import *
8
8
  from .loader import *
9
9
  from .dumper import *
10
10
 
11
- __version__ = '6.0.2'
11
+ __version__ = '6.0.3'
12
12
  try:
13
13
  from .cyaml import *
14
14
  __with_libyaml__ = True
@@ -172,7 +172,8 @@ class DefaultAzureCredential(ChainedTokenCredential):
172
172
 
173
173
  process_timeout = kwargs.pop("process_timeout", 10)
174
174
  require_envvar = kwargs.pop("require_envvar", False)
175
- if require_envvar and not os.environ.get(EnvironmentVariables.AZURE_TOKEN_CREDENTIALS):
175
+ token_credentials_env = os.environ.get(EnvironmentVariables.AZURE_TOKEN_CREDENTIALS, "").strip().lower()
176
+ if require_envvar and not token_credentials_env:
176
177
  raise ValueError(
177
178
  "AZURE_TOKEN_CREDENTIALS environment variable is required but is not set or is empty. "
178
179
  "Set it to 'dev', 'prod', or a specific credential name."
@@ -274,18 +275,16 @@ class DefaultAzureCredential(ChainedTokenCredential):
274
275
  ManagedIdentityCredential(
275
276
  client_id=managed_identity_client_id,
276
277
  _exclude_workload_identity_credential=exclude_workload_identity_credential,
278
+ _enable_imds_probe=token_credentials_env != "managedidentitycredential",
277
279
  **kwargs,
278
280
  )
279
281
  )
280
282
  if not exclude_shared_token_cache_credential and SharedTokenCacheCredential.supported():
281
- try:
282
- # username and/or tenant_id are only required when the cache contains tokens for multiple identities
283
- shared_cache = SharedTokenCacheCredential(
284
- username=shared_cache_username, tenant_id=shared_cache_tenant_id, authority=authority, **kwargs
285
- )
286
- credentials.append(shared_cache)
287
- except Exception as ex: # pylint:disable=broad-except
288
- _LOGGER.info("Shared token cache is unavailable: '%s'", ex)
283
+ # username and/or tenant_id are only required when the cache contains tokens for multiple identities
284
+ shared_cache = SharedTokenCacheCredential(
285
+ username=shared_cache_username, tenant_id=shared_cache_tenant_id, authority=authority, **kwargs
286
+ )
287
+ credentials.append(shared_cache)
289
288
  if not exclude_visual_studio_code_credential:
290
289
  credentials.append(VisualStudioCodeCredential(tenant_id=vscode_tenant_id))
291
290
  if not exclude_cli_credential:
@@ -82,6 +82,10 @@ def _check_forbidden_response(ex: HttpResponseError) -> None:
82
82
 
83
83
  class ImdsCredential(MsalManagedIdentityClient):
84
84
  def __init__(self, **kwargs: Any) -> None:
85
+ # If set to True/False, _enable_imds_probe forces whether or not the credential
86
+ # probes for the IMDS endpoint before attempting to get a token. If None (the default),
87
+ # the credential probes only if it's part of a ChainedTokenCredential chain.
88
+ self._enable_imds_probe = kwargs.pop("_enable_imds_probe", None)
85
89
  super().__init__(retry_policy_class=ImdsRetryPolicy, **dict(PIPELINE_SETTINGS, **kwargs))
86
90
  self._config = kwargs
87
91
 
@@ -102,9 +106,9 @@ class ImdsCredential(MsalManagedIdentityClient):
102
106
 
103
107
  def _request_token(self, *scopes: str, **kwargs: Any) -> AccessTokenInfo:
104
108
 
105
- if within_credential_chain.get() and not self._endpoint_available:
106
- # If within a chain (e.g. DefaultAzureCredential), we do a quick check to see if the IMDS endpoint
107
- # is available to avoid hanging for a long time if the endpoint isn't available.
109
+ do_probe = self._enable_imds_probe if self._enable_imds_probe is not None else within_credential_chain.get()
110
+ if do_probe and not self._endpoint_available:
111
+ # Probe to see if the IMDS endpoint is available to avoid hanging for a long time if it's not.
108
112
  try:
109
113
  client = ManagedIdentityClient(_get_request, **dict(PIPELINE_SETTINGS, **self._config))
110
114
  client.request_token(*scopes, connection_timeout=1, retry_total=0)
@@ -76,6 +76,7 @@ class ManagedIdentityCredential:
76
76
  user_identity_info = validate_identity_config(client_id, identity_config)
77
77
  self._credential: Optional[SupportsTokenInfo] = None
78
78
  exclude_workload_identity = kwargs.pop("_exclude_workload_identity_credential", False)
79
+ self._enable_imds_probe = kwargs.pop("_enable_imds_probe", None)
79
80
  managed_identity_type = None
80
81
 
81
82
  if os.environ.get(EnvironmentVariables.IDENTITY_ENDPOINT):
@@ -136,7 +137,12 @@ class ManagedIdentityCredential:
136
137
  managed_identity_type = "IMDS"
137
138
  from .imds import ImdsCredential
138
139
 
139
- self._credential = ImdsCredential(client_id=client_id, identity_config=identity_config, **kwargs)
140
+ self._credential = ImdsCredential(
141
+ client_id=client_id,
142
+ identity_config=identity_config,
143
+ _enable_imds_probe=self._enable_imds_probe,
144
+ **kwargs,
145
+ )
140
146
 
141
147
  if managed_identity_type:
142
148
  log_msg = f"{self.__class__.__name__} will use {managed_identity_type}"
@@ -198,9 +198,9 @@ class _SharedTokenCacheCredential(SharedTokenCacheBase):
198
198
  return token
199
199
  except Exception as e: # pylint: disable=broad-except
200
200
  if within_dac.get():
201
- raise CredentialUnavailableError( # pylint: disable=raise-missing-from
201
+ raise CredentialUnavailableError(
202
202
  message=getattr(e, "message", str(e)), response=getattr(e, "response", None)
203
- )
203
+ ) from e
204
204
  raise
205
205
 
206
206
  raise CredentialUnavailableError(message=NO_TOKEN.format(account.get("username")))
@@ -203,7 +203,7 @@ class InteractiveCredential(MsalCredential, ABC):
203
203
  return token
204
204
  except Exception as ex: # pylint:disable=broad-except
205
205
  if not (isinstance(ex, AuthenticationRequiredError) and allow_prompt):
206
- _LOGGER.warning(
206
+ _LOGGER.warning( # pylint: disable=do-not-log-raised-errors
207
207
  "%s.%s failed: %s",
208
208
  self.__class__.__name__,
209
209
  base_method_name,
@@ -225,7 +225,7 @@ class InteractiveCredential(MsalCredential, ABC):
225
225
  # this may be the first authentication, or the user may have authenticated a different identity
226
226
  self._auth_record = _build_auth_record(result)
227
227
  except Exception as ex:
228
- _LOGGER.warning(
228
+ _LOGGER.warning( # pylint: disable=do-not-log-raised-errors
229
229
  "%s.%s failed: %s",
230
230
  self.__class__.__name__,
231
231
  base_method_name,
@@ -61,7 +61,7 @@ class MsalManagedIdentityClient(abc.ABC): # pylint:disable=client-accepts-api-v
61
61
  )
62
62
  error_desc = ""
63
63
  if result and "error" in result:
64
- error_desc = cast(str, result["error"])
64
+ error_desc = f"Token request error: ({result['error']}) {result.get('error_description', '')}"
65
65
  error_message = self.get_unavailable_message(error_desc)
66
66
  raise CredentialUnavailableError(error_message)
67
67
 
@@ -2,4 +2,4 @@
2
2
  # Copyright (c) Microsoft Corporation.
3
3
  # Licensed under the MIT License.
4
4
  # ------------------------------------
5
- VERSION = "1.25.0"
5
+ VERSION = "1.25.1"
@@ -144,7 +144,8 @@ class DefaultAzureCredential(ChainedTokenCredential):
144
144
 
145
145
  process_timeout = kwargs.pop("process_timeout", 10)
146
146
  require_envvar = kwargs.pop("require_envvar", False)
147
- if require_envvar and not os.environ.get(EnvironmentVariables.AZURE_TOKEN_CREDENTIALS):
147
+ token_credentials_env = os.environ.get(EnvironmentVariables.AZURE_TOKEN_CREDENTIALS, "").strip().lower()
148
+ if require_envvar and not token_credentials_env:
148
149
  raise ValueError(
149
150
  "AZURE_TOKEN_CREDENTIALS environment variable is required but is not set or is empty. "
150
151
  "Set it to 'dev', 'prod', or a specific credential name."
@@ -235,18 +236,16 @@ class DefaultAzureCredential(ChainedTokenCredential):
235
236
  ManagedIdentityCredential(
236
237
  client_id=managed_identity_client_id,
237
238
  _exclude_workload_identity_credential=exclude_workload_identity_credential,
239
+ _enable_imds_probe=token_credentials_env != "managedidentitycredential",
238
240
  **kwargs,
239
241
  )
240
242
  )
241
243
  if not exclude_shared_token_cache_credential and SharedTokenCacheCredential.supported():
242
- try:
243
- # username and/or tenant_id are only required when the cache contains tokens for multiple identities
244
- shared_cache = SharedTokenCacheCredential(
245
- username=shared_cache_username, tenant_id=shared_cache_tenant_id, authority=authority, **kwargs
246
- )
247
- credentials.append(shared_cache)
248
- except Exception as ex: # pylint:disable=broad-except
249
- _LOGGER.info("Shared token cache is unavailable: '%s'", ex)
244
+ # username and/or tenant_id are only required when the cache contains tokens for multiple identities
245
+ shared_cache = SharedTokenCacheCredential(
246
+ username=shared_cache_username, tenant_id=shared_cache_tenant_id, authority=authority, **kwargs
247
+ )
248
+ credentials.append(shared_cache)
250
249
  if not exclude_visual_studio_code_credential:
251
250
  credentials.append(VisualStudioCodeCredential(tenant_id=vscode_tenant_id))
252
251
  if not exclude_cli_credential:
@@ -45,6 +45,10 @@ class ImdsCredential(AsyncContextManager, GetTokenMixin):
45
45
  def __init__(self, **kwargs: Any) -> None:
46
46
  super().__init__()
47
47
 
48
+ # If set to True/False, _enable_imds_probe forces whether or not the credential
49
+ # probes for the IMDS endpoint before attempting to get a token. If None (the default),
50
+ # the credential probes only if it's part of a ChainedTokenCredential chain.
51
+ self._enable_imds_probe = kwargs.pop("_enable_imds_probe", None)
48
52
  kwargs["retry_policy_class"] = AsyncImdsRetryPolicy
49
53
  self._client = AsyncManagedIdentityClient(_get_request, **dict(PIPELINE_SETTINGS, **kwargs))
50
54
  if EnvironmentVariables.AZURE_POD_IDENTITY_AUTHORITY_HOST in os.environ:
@@ -65,9 +69,9 @@ class ImdsCredential(AsyncContextManager, GetTokenMixin):
65
69
 
66
70
  async def _request_token(self, *scopes: str, **kwargs: Any) -> AccessTokenInfo:
67
71
 
68
- if within_credential_chain.get() and not self._endpoint_available:
69
- # If within a chain (e.g. DefaultAzureCredential), we do a quick check to see if the IMDS endpoint
70
- # is available to avoid hanging for a long time if the endpoint isn't available.
72
+ do_probe = self._enable_imds_probe if self._enable_imds_probe is not None else within_credential_chain.get()
73
+ if do_probe and not self._endpoint_available:
74
+ # Probe to see if the IMDS endpoint is available to avoid hanging for a long time if it's not.
71
75
  try:
72
76
  await self._client.request_token(*scopes, connection_timeout=1, retry_total=0)
73
77
  self._endpoint_available = True
@@ -49,6 +49,7 @@ class ManagedIdentityCredential(AsyncContextManager):
49
49
  user_identity_info = validate_identity_config(client_id, identity_config)
50
50
  self._credential: Optional[AsyncSupportsTokenInfo] = None
51
51
  exclude_workload_identity = kwargs.pop("_exclude_workload_identity_credential", False)
52
+ self._enable_imds_probe = kwargs.pop("_enable_imds_probe", None)
52
53
  managed_identity_type = None
53
54
  if os.environ.get(EnvironmentVariables.IDENTITY_ENDPOINT):
54
55
  if os.environ.get(EnvironmentVariables.IDENTITY_HEADER):
@@ -108,7 +109,12 @@ class ManagedIdentityCredential(AsyncContextManager):
108
109
  managed_identity_type = "IMDS"
109
110
  from .imds import ImdsCredential
110
111
 
111
- self._credential = ImdsCredential(client_id=client_id, identity_config=identity_config, **kwargs)
112
+ self._credential = ImdsCredential(
113
+ client_id=client_id,
114
+ identity_config=identity_config,
115
+ _enable_imds_probe=self._enable_imds_probe,
116
+ **kwargs,
117
+ )
112
118
 
113
119
  if managed_identity_type:
114
120
  log_msg = f"{self.__class__.__name__} will use {managed_identity_type}"
@@ -151,9 +151,9 @@ class SharedTokenCacheCredential(SharedTokenCacheBase, AsyncContextManager):
151
151
  return token
152
152
  except Exception as e: # pylint: disable=broad-except
153
153
  if within_dac.get():
154
- raise CredentialUnavailableError( # pylint: disable=raise-missing-from
154
+ raise CredentialUnavailableError(
155
155
  message=getattr(e, "message", str(e)), response=getattr(e, "response", None)
156
- )
156
+ ) from e
157
157
  raise
158
158
  raise CredentialUnavailableError(message=NO_TOKEN.format(account.get("username")))
159
159