py2docfx 0.1.11rc1981066__py3-none-any.whl → 0.1.11rc1997820__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 (146) hide show
  1. py2docfx/__main__.py +24 -15
  2. py2docfx/convert_prepare/environment.py +13 -10
  3. py2docfx/convert_prepare/generate_document.py +6 -6
  4. py2docfx/convert_prepare/get_source.py +7 -7
  5. py2docfx/convert_prepare/git.py +10 -13
  6. py2docfx/convert_prepare/install_package.py +2 -2
  7. py2docfx/convert_prepare/pack.py +7 -10
  8. py2docfx/convert_prepare/package_info.py +3 -3
  9. py2docfx/convert_prepare/pip_utils.py +12 -14
  10. py2docfx/convert_prepare/post_process/merge_toc.py +3 -2
  11. py2docfx/convert_prepare/sphinx_caller.py +34 -12
  12. py2docfx/convert_prepare/tests/test_environment.py +0 -3
  13. py2docfx/convert_prepare/tests/test_generate_document.py +4 -2
  14. py2docfx/convert_prepare/tests/test_get_source.py +22 -14
  15. py2docfx/convert_prepare/tests/test_pack.py +6 -3
  16. py2docfx/convert_prepare/tests/test_params.py +0 -1
  17. py2docfx/convert_prepare/tests/test_sphinx_caller.py +10 -8
  18. py2docfx/convert_prepare/tests/test_subpackage.py +1 -0
  19. py2docfx/docfx_yaml/build_finished.py +1 -1
  20. py2docfx/docfx_yaml/logger.py +56 -55
  21. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/authorization_code.py +1 -1
  22. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azd_cli.py +20 -14
  23. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_arc.py +1 -1
  24. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_cli.py +36 -14
  25. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_powershell.py +1 -1
  26. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/chained.py +2 -2
  27. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +4 -3
  28. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +2 -2
  29. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/managed_identity.py +1 -1
  30. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/__init__.py +2 -0
  31. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/auth_code_redirect_handler.py +1 -1
  32. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/decorators.py +15 -7
  33. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +1 -1
  34. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/managed_identity_client.py +0 -1
  35. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_client.py +1 -1
  36. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_managed_identity_client.py +2 -1
  37. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/shared_token_cache.py +3 -3
  38. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/utils.py +17 -2
  39. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
  40. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azd_cli.py +14 -11
  41. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_cli.py +30 -12
  42. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +2 -2
  43. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +3 -3
  44. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/managed_identity.py +1 -1
  45. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/decorators.py +15 -7
  46. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/managed_identity_client.py +1 -1
  47. py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
  48. py2docfx/venv/venv1/Lib/site-packages/google/api/annotations_pb2.py +7 -4
  49. py2docfx/venv/venv1/Lib/site-packages/google/api/auth_pb2.py +6 -3
  50. py2docfx/venv/venv1/Lib/site-packages/google/api/backend_pb2.py +14 -7
  51. py2docfx/venv/venv1/Lib/site-packages/google/api/billing_pb2.py +6 -3
  52. py2docfx/venv/venv1/Lib/site-packages/google/api/client_pb2.py +47 -38
  53. py2docfx/venv/venv1/Lib/site-packages/google/api/config_change_pb2.py +6 -3
  54. py2docfx/venv/venv1/Lib/site-packages/google/api/consumer_pb2.py +6 -3
  55. py2docfx/venv/venv1/Lib/site-packages/google/api/context_pb2.py +6 -3
  56. py2docfx/venv/venv1/Lib/site-packages/google/api/control_pb2.py +6 -4
  57. py2docfx/venv/venv1/Lib/site-packages/google/api/distribution_pb2.py +7 -5
  58. py2docfx/venv/venv1/Lib/site-packages/google/api/documentation_pb2.py +6 -3
  59. py2docfx/venv/venv1/Lib/site-packages/google/api/endpoint_pb2.py +6 -3
  60. py2docfx/venv/venv1/Lib/site-packages/google/api/error_reason_pb2.py +6 -3
  61. py2docfx/venv/venv1/Lib/site-packages/google/api/field_behavior_pb2.py +8 -6
  62. py2docfx/venv/venv1/Lib/site-packages/google/api/field_info_pb2.py +6 -4
  63. py2docfx/venv/venv1/Lib/site-packages/google/api/http_pb2.py +7 -4
  64. py2docfx/venv/venv1/Lib/site-packages/google/api/httpbody_pb2.py +6 -4
  65. py2docfx/venv/venv1/Lib/site-packages/google/api/label_pb2.py +7 -4
  66. py2docfx/venv/venv1/Lib/site-packages/google/api/launch_stage_pb2.py +6 -3
  67. py2docfx/venv/venv1/Lib/site-packages/google/api/log_pb2.py +6 -4
  68. py2docfx/venv/venv1/Lib/site-packages/google/api/logging_pb2.py +6 -3
  69. py2docfx/venv/venv1/Lib/site-packages/google/api/metric_pb2.py +12 -9
  70. py2docfx/venv/venv1/Lib/site-packages/google/api/monitored_resource_pb2.py +15 -10
  71. py2docfx/venv/venv1/Lib/site-packages/google/api/monitoring_pb2.py +6 -3
  72. py2docfx/venv/venv1/Lib/site-packages/google/api/policy_pb2.py +7 -5
  73. py2docfx/venv/venv1/Lib/site-packages/google/api/quota_pb2.py +10 -7
  74. py2docfx/venv/venv1/Lib/site-packages/google/api/resource_pb2.py +7 -5
  75. py2docfx/venv/venv1/Lib/site-packages/google/api/routing_pb2.py +6 -4
  76. py2docfx/venv/venv1/Lib/site-packages/google/api/service_pb2.py +15 -12
  77. py2docfx/venv/venv1/Lib/site-packages/google/api/source_info_pb2.py +6 -4
  78. py2docfx/venv/venv1/Lib/site-packages/google/api/system_parameter_pb2.py +6 -3
  79. py2docfx/venv/venv1/Lib/site-packages/google/api/usage_pb2.py +6 -3
  80. py2docfx/venv/venv1/Lib/site-packages/google/api/visibility_pb2.py +7 -5
  81. py2docfx/venv/venv1/Lib/site-packages/google/cloud/extended_operations_pb2.py +6 -4
  82. py2docfx/venv/venv1/Lib/site-packages/google/cloud/location/locations_pb2.py +18 -13
  83. py2docfx/venv/venv1/Lib/site-packages/google/gapic/metadata/gapic_metadata_pb2.py +31 -26
  84. py2docfx/venv/venv1/Lib/site-packages/google/logging/type/http_request_pb2.py +6 -4
  85. py2docfx/venv/venv1/Lib/site-packages/google/logging/type/log_severity_pb2.py +6 -3
  86. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc.py +2 -1
  87. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc_pb2.py +11 -10
  88. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2.py +20 -17
  89. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2_grpc.py +1 -2
  90. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto.py +2 -1
  91. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto_pb2.py +22 -19
  92. py2docfx/venv/venv1/Lib/site-packages/google/rpc/code_pb2.py +6 -3
  93. py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/attribute_context_pb2.py +20 -16
  94. py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/audit_context_pb2.py +7 -5
  95. py2docfx/venv/venv1/Lib/site-packages/google/rpc/error_details_pb2.py +21 -19
  96. py2docfx/venv/venv1/Lib/site-packages/google/rpc/http_pb2.py +6 -3
  97. py2docfx/venv/venv1/Lib/site-packages/google/rpc/status_pb2.py +6 -4
  98. py2docfx/venv/venv1/Lib/site-packages/google/type/calendar_period_pb2.py +6 -3
  99. py2docfx/venv/venv1/Lib/site-packages/google/type/color_pb2.py +6 -4
  100. py2docfx/venv/venv1/Lib/site-packages/google/type/date_pb2.py +6 -3
  101. py2docfx/venv/venv1/Lib/site-packages/google/type/datetime_pb2.py +6 -4
  102. py2docfx/venv/venv1/Lib/site-packages/google/type/dayofweek_pb2.py +6 -3
  103. py2docfx/venv/venv1/Lib/site-packages/google/type/decimal_pb2.py +6 -3
  104. py2docfx/venv/venv1/Lib/site-packages/google/type/expr_pb2.py +6 -3
  105. py2docfx/venv/venv1/Lib/site-packages/google/type/fraction_pb2.py +6 -3
  106. py2docfx/venv/venv1/Lib/site-packages/google/type/interval_pb2.py +6 -4
  107. py2docfx/venv/venv1/Lib/site-packages/google/type/latlng_pb2.py +6 -3
  108. py2docfx/venv/venv1/Lib/site-packages/google/type/localized_text_pb2.py +6 -3
  109. py2docfx/venv/venv1/Lib/site-packages/google/type/money_pb2.py +6 -3
  110. py2docfx/venv/venv1/Lib/site-packages/google/type/month_pb2.py +6 -3
  111. py2docfx/venv/venv1/Lib/site-packages/google/type/phone_number_pb2.py +6 -3
  112. py2docfx/venv/venv1/Lib/site-packages/google/type/postal_address_pb2.py +6 -3
  113. py2docfx/venv/venv1/Lib/site-packages/google/type/quaternion_pb2.py +6 -3
  114. py2docfx/venv/venv1/Lib/site-packages/google/type/timeofday_pb2.py +6 -3
  115. py2docfx/venv/venv1/Lib/site-packages/psutil/__init__.py +122 -201
  116. py2docfx/venv/venv1/Lib/site-packages/psutil/_common.py +84 -128
  117. py2docfx/venv/venv1/Lib/site-packages/psutil/_psaix.py +24 -38
  118. py2docfx/venv/venv1/Lib/site-packages/psutil/_psbsd.py +44 -58
  119. py2docfx/venv/venv1/Lib/site-packages/psutil/_pslinux.py +170 -254
  120. py2docfx/venv/venv1/Lib/site-packages/psutil/_psosx.py +8 -16
  121. py2docfx/venv/venv1/Lib/site-packages/psutil/_psposix.py +13 -49
  122. py2docfx/venv/venv1/Lib/site-packages/psutil/_pssunos.py +41 -60
  123. py2docfx/venv/venv1/Lib/site-packages/psutil/_pswindows.py +75 -145
  124. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__init__.py +105 -193
  125. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_aix.py +2 -2
  126. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_bsd.py +27 -26
  127. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_connections.py +16 -17
  128. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_contracts.py +5 -19
  129. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_linux.py +153 -211
  130. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_memleaks.py +0 -6
  131. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_misc.py +22 -207
  132. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_osx.py +9 -4
  133. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_posix.py +8 -15
  134. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process.py +104 -184
  135. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process_all.py +28 -36
  136. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_scripts.py +240 -0
  137. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_sunos.py +1 -1
  138. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_system.py +44 -50
  139. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_testutils.py +23 -33
  140. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_unicode.py +8 -67
  141. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_windows.py +32 -52
  142. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/METADATA +1 -1
  143. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/RECORD +145 -145
  144. py2docfx/venv/venv1/Lib/site-packages/psutil/_compat.py +0 -477
  145. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/WHEEL +0 -0
  146. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/top_level.txt +0 -0
@@ -89,7 +89,7 @@ class ImdsCredential(MsalManagedIdentityClient):
89
89
  # IMDS responded
90
90
  _check_forbidden_response(ex)
91
91
  self._endpoint_available = True
92
- except Exception as ex: # pylint:disable=broad-except
92
+ except Exception as ex:
93
93
  error_message = (
94
94
  "ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint."
95
95
  )
@@ -119,7 +119,7 @@ class ImdsCredential(MsalManagedIdentityClient):
119
119
  raise ClientAuthenticationError(message=ex.message, response=ex.response) from ex
120
120
  except json.decoder.JSONDecodeError as ex:
121
121
  raise CredentialUnavailableError(message="ManagedIdentityCredential authentication unavailable.") from ex
122
- except Exception as ex: # pylint:disable=broad-except
122
+ except Exception as ex:
123
123
  # if anything else was raised, assume the endpoint is unavailable
124
124
  error_message = "ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint."
125
125
  raise CredentialUnavailableError(error_message) from ex
@@ -108,7 +108,7 @@ class ManagedIdentityCredential:
108
108
  self._credential = WorkloadIdentityCredential(
109
109
  tenant_id=os.environ[EnvironmentVariables.AZURE_TENANT_ID],
110
110
  client_id=workload_client_id,
111
- file=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
111
+ token_file_path=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
112
112
  **kwargs,
113
113
  )
114
114
  else:
@@ -13,6 +13,7 @@ from .utils import (
13
13
  normalize_authority,
14
14
  resolve_tenant,
15
15
  validate_scope,
16
+ validate_subscription,
16
17
  validate_tenant_id,
17
18
  within_credential_chain,
18
19
  within_dac,
@@ -49,6 +50,7 @@ __all__ = [
49
50
  "normalize_authority",
50
51
  "resolve_tenant",
51
52
  "validate_scope",
53
+ "validate_subscription",
52
54
  "within_credential_chain",
53
55
  "within_dac",
54
56
  "wrap_exceptions",
@@ -28,7 +28,7 @@ class AuthCodeRedirectHandler(BaseHTTPRequestHandler):
28
28
 
29
29
  self.wfile.write(b"Authentication complete. You can close this window.")
30
30
 
31
- def log_message(self, format, *args): # pylint: disable=redefined-builtin,unused-argument
31
+ def log_message(self, format, *args): # pylint: disable=redefined-builtin
32
32
  pass # this prevents server dumping messages to stdout
33
33
 
34
34
 
@@ -22,24 +22,32 @@ def log_get_token(fn):
22
22
  try:
23
23
  token = fn(*args, **kwargs)
24
24
  _LOGGER.log(
25
- logging.DEBUG if within_credential_chain.get() else logging.INFO, "%s succeeded", fn.__qualname__
25
+ logging.DEBUG if within_credential_chain.get() else logging.INFO,
26
+ "%s succeeded",
27
+ fn.__qualname__,
26
28
  )
27
29
  if _LOGGER.isEnabledFor(logging.DEBUG):
28
30
  try:
29
- base64_meta_data = token.token.split(".")[1].encode("utf-8") + b"=="
30
- json_bytes = base64.decodebytes(base64_meta_data)
31
+ base64_meta_data = token.token.split(".")[1]
32
+ padding_needed = -len(base64_meta_data) % 4
33
+ if padding_needed:
34
+ base64_meta_data += "=" * padding_needed
35
+ json_bytes = base64.urlsafe_b64decode(base64_meta_data)
31
36
  json_string = json_bytes.decode("utf-8")
32
37
  json_dict = json.loads(json_string)
33
38
  upn = json_dict.get("upn", "unavailableUpn")
39
+ appid = json_dict.get("appid", "<unavailable>")
40
+ tid = json_dict.get("tid", "<unavailable>")
41
+ oid = json_dict.get("oid", "<unavailable>")
34
42
  log_string = (
35
- "[Authenticated account] Client ID: {}. Tenant ID: {}. User Principal Name: {}. "
36
- "Object ID (user): {}".format(json_dict["appid"], json_dict["tid"], upn, json_dict["oid"])
43
+ f"[Authenticated account] Client ID: {appid}. "
44
+ f"Tenant ID: {tid}. User Principal Name: {upn}. Object ID (user): {oid}"
37
45
  )
38
46
  _LOGGER.debug(log_string)
39
47
  except Exception as ex: # pylint: disable=broad-except
40
48
  _LOGGER.debug("Failed to log the account information: %s", ex, exc_info=True)
41
49
  return token
42
- except Exception as ex: # pylint: disable=broad-except
50
+ except Exception as ex:
43
51
  _LOGGER.log(
44
52
  logging.DEBUG if within_credential_chain.get() else logging.WARNING,
45
53
  "%s failed: %s",
@@ -67,7 +75,7 @@ def wrap_exceptions(fn):
67
75
  return fn(*args, **kwargs)
68
76
  except ClientAuthenticationError:
69
77
  raise
70
- except Exception as ex: # pylint:disable=broad-except
78
+ except Exception as ex:
71
79
  auth_error = ClientAuthenticationError(message="Authentication failed: {}".format(ex))
72
80
  raise auth_error from ex
73
81
 
@@ -224,7 +224,7 @@ class InteractiveCredential(MsalCredential, ABC):
224
224
 
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
- except Exception as ex: # pylint:disable=broad-except
227
+ except Exception as ex:
228
228
  _LOGGER.warning(
229
229
  "%s.%s failed: %s",
230
230
  self.__class__.__name__,
@@ -19,7 +19,6 @@ from .._internal.pipeline import build_pipeline
19
19
 
20
20
 
21
21
  class ManagedIdentityClientBase(abc.ABC):
22
- # pylint:disable=missing-client-constructor-parameter-credential
23
22
  def __init__(
24
23
  self,
25
24
  request_factory: Callable[[str, dict], HttpRequest],
@@ -7,7 +7,7 @@ from typing import Any, Dict, Optional, Union
7
7
 
8
8
  from azure.core.exceptions import ClientAuthenticationError
9
9
  from azure.core.pipeline.policies import ContentDecodePolicy
10
- from azure.core.pipeline.transport import ( # pylint:disable=unknown-option-value,no-legacy-azure-core-http-response-import
10
+ from azure.core.pipeline.transport import ( # pylint:disable=no-legacy-azure-core-http-response-import
11
11
  HttpRequest,
12
12
  HttpResponse,
13
13
  )
@@ -59,6 +59,7 @@ class MsalManagedIdentityClient(abc.ABC): # pylint:disable=client-accepts-api-v
59
59
  token_type=result.get("token_type", "Bearer"),
60
60
  refresh_on=refresh_on,
61
61
  )
62
+ error_desc = ""
62
63
  if result and "error" in result:
63
64
  error_desc = cast(str, result["error"])
64
65
  error_message = self.get_unavailable_message(error_desc)
@@ -186,7 +187,7 @@ class MsalManagedIdentityClient(abc.ABC): # pylint:disable=client-accepts-api-v
186
187
  exc_info=_LOGGER.isEnabledFor(logging.DEBUG),
187
188
  )
188
189
  raise ClientAuthenticationError(self.get_unavailable_message(str(ex))) from ex
189
- except Exception as ex: # pylint:disable=broad-except
190
+ except Exception as ex:
190
191
  _LOGGER.log(
191
192
  logging.DEBUG if within_credential_chain.get() else logging.WARNING,
192
193
  "%s.%s failed: %s",
@@ -88,7 +88,7 @@ class SharedTokenCacheBase(ABC): # pylint: disable=too-many-instance-attributes
88
88
  authority: Optional[str] = None,
89
89
  tenant_id: Optional[str] = None,
90
90
  **kwargs: Any
91
- ) -> None: # pylint:disable=unused-argument
91
+ ) -> None:
92
92
  self._authority = normalize_authority(authority) if authority else get_default_authority()
93
93
  environment = urlparse(self._authority).netloc
94
94
  self._environment_aliases = KNOWN_ALIASES.get(environment) or frozenset((environment,))
@@ -246,7 +246,7 @@ class SharedTokenCacheBase(ABC): # pylint: disable=too-many-instance-attributes
246
246
  return AccessTokenInfo(
247
247
  token["secret"], expires_on, token_type=token.get("token_type", "Bearer"), refresh_on=refresh_on
248
248
  )
249
- except Exception as ex: # pylint:disable=broad-except
249
+ except Exception as ex:
250
250
  message = "Error accessing cached data: {}".format(ex)
251
251
  raise CredentialUnavailableError(message=message) from ex
252
252
 
@@ -262,7 +262,7 @@ class SharedTokenCacheBase(ABC): # pylint: disable=too-many-instance-attributes
262
262
  msal.TokenCache.CredentialType.REFRESH_TOKEN, query={"home_account_id": account["home_account_id"]}
263
263
  )
264
264
  return [token["secret"] for token in cache_entries if "secret" in token]
265
- except Exception as ex: # pylint:disable=broad-except
265
+ except Exception as ex:
266
266
  message = "Error accessing cached data: {}".format(ex)
267
267
  raise CredentialUnavailableError(message=message) from ex
268
268
 
@@ -20,6 +20,7 @@ _LOGGER = logging.getLogger(__name__)
20
20
 
21
21
  VALID_TENANT_ID_CHARACTERS = frozenset(ascii_letters + digits + "-.")
22
22
  VALID_SCOPE_CHARACTERS = frozenset(ascii_letters + digits + "_-.:/")
23
+ VALID_SUBSCRIPTION_CHARACTERS = frozenset(ascii_letters + digits + "_-. ")
23
24
 
24
25
 
25
26
  def normalize_authority(authority: str) -> str:
@@ -68,7 +69,21 @@ def validate_tenant_id(tenant_id: str) -> None:
68
69
  if not tenant_id or any(c not in VALID_TENANT_ID_CHARACTERS for c in tenant_id):
69
70
  raise ValueError(
70
71
  "Invalid tenant ID provided. You can locate your tenant ID by following the instructions here: "
71
- + "https://learn.microsoft.com/partner-center/find-ids-and-domain-names"
72
+ "https://learn.microsoft.com/partner-center/find-ids-and-domain-names"
73
+ )
74
+
75
+
76
+ def validate_subscription(subscription: str) -> None:
77
+ """Raise ValueError if subscription is empty or contains a character invalid for a subscription name/ID.
78
+
79
+ :param str subscription: subscription ID to validate
80
+ :raises: ValueError if subscription is empty or contains a character invalid for a subscription ID.
81
+ """
82
+ if not subscription or any(c not in VALID_SUBSCRIPTION_CHARACTERS for c in subscription):
83
+ raise ValueError(
84
+ f"Subscription '{subscription}' contains invalid characters. If this is the name of a subscription, use "
85
+ "its ID instead. You can locate your subscription by following the instructions listed here: "
86
+ "https://learn.microsoft.com/azure/azure-portal/get-subscription-tenant-id"
72
87
  )
73
88
 
74
89
 
@@ -77,7 +92,7 @@ def resolve_tenant(
77
92
  tenant_id: Optional[str] = None,
78
93
  *,
79
94
  additionally_allowed_tenants: Optional[List[str]] = None,
80
- **_
95
+ **_,
81
96
  ) -> str:
82
97
  """Returns the correct tenant for a token request given a credential's configuration.
83
98
 
@@ -2,4 +2,4 @@
2
2
  # Copyright (c) Microsoft Corporation.
3
3
  # Licensed under the MIT License.
4
4
  # ------------------------------------
5
- VERSION = "1.19.0"
5
+ VERSION = "1.20.0"
@@ -3,6 +3,7 @@
3
3
  # Licensed under the MIT License.
4
4
  # ------------------------------------
5
5
  import asyncio
6
+ import logging
6
7
  import os
7
8
  import shutil
8
9
  import sys
@@ -26,6 +27,9 @@ from ..._credentials.azd_cli import (
26
27
  from ..._internal import resolve_tenant, within_dac, validate_tenant_id, validate_scope
27
28
 
28
29
 
30
+ _LOGGER = logging.getLogger(__name__)
31
+
32
+
29
33
  class AzureDeveloperCliCredential(AsyncContextManager):
30
34
  """Authenticates by requesting a token from the Azure Developer CLI.
31
35
 
@@ -153,8 +157,9 @@ class AzureDeveloperCliCredential(AsyncContextManager):
153
157
  for scope in scopes:
154
158
  validate_scope(scope)
155
159
 
156
- commandString = " --scope ".join(scopes)
157
- command = COMMAND_LINE.format(commandString)
160
+ command_args = COMMAND_LINE.copy()
161
+ for scope in scopes:
162
+ command_args += ["--scope", scope]
158
163
  tenant = resolve_tenant(
159
164
  default_tenant=self.tenant_id,
160
165
  tenant_id=tenant_id,
@@ -163,8 +168,8 @@ class AzureDeveloperCliCredential(AsyncContextManager):
163
168
  )
164
169
 
165
170
  if tenant:
166
- command += " --tenant-id " + tenant
167
- output = await _run_command(command, self._process_timeout)
171
+ command_args += ["--tenant-id", tenant]
172
+ output = await _run_command(command_args, self._process_timeout)
168
173
 
169
174
  token = parse_token(output)
170
175
  if not token:
@@ -184,19 +189,17 @@ class AzureDeveloperCliCredential(AsyncContextManager):
184
189
  """Calling this method is unnecessary"""
185
190
 
186
191
 
187
- async def _run_command(command: str, timeout: int) -> str:
192
+ async def _run_command(command_args: List[str], timeout: int) -> str:
188
193
  # Ensure executable exists in PATH first. This avoids a subprocess call that would fail anyway.
189
- if shutil.which(EXECUTABLE_NAME) is None:
194
+ azd_path = shutil.which(EXECUTABLE_NAME)
195
+ if not azd_path:
190
196
  raise CredentialUnavailableError(message=CLI_NOT_FOUND)
191
197
 
192
- if sys.platform.startswith("win"):
193
- args = ("cmd", "/c " + command)
194
- else:
195
- args = ("/bin/sh", "-c", command)
196
-
198
+ args = [azd_path] + command_args
197
199
  working_directory = get_safe_working_dir()
198
200
 
199
201
  try:
202
+ _LOGGER.debug("Executing subprocess with the following arguments %s", args)
200
203
  proc = await asyncio.create_subprocess_exec(
201
204
  *args,
202
205
  stdout=asyncio.subprocess.PIPE,
@@ -3,6 +3,7 @@
3
3
  # Licensed under the MIT License.
4
4
  # ------------------------------------
5
5
  import asyncio
6
+ import logging
6
7
  import os
7
8
  import shutil
8
9
  import sys
@@ -23,7 +24,17 @@ from ..._credentials.azure_cli import (
23
24
  parse_token,
24
25
  sanitize_output,
25
26
  )
26
- from ..._internal import _scopes_to_resource, resolve_tenant, within_dac, validate_tenant_id, validate_scope
27
+ from ..._internal import (
28
+ _scopes_to_resource,
29
+ resolve_tenant,
30
+ within_dac,
31
+ validate_tenant_id,
32
+ validate_scope,
33
+ validate_subscription,
34
+ )
35
+
36
+
37
+ _LOGGER = logging.getLogger(__name__)
27
38
 
28
39
 
29
40
  class AzureCliCredential(AsyncContextManager):
@@ -32,6 +43,8 @@ class AzureCliCredential(AsyncContextManager):
32
43
  This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity.
33
44
 
34
45
  :keyword str tenant_id: Optional tenant to include in the token request.
46
+ :keyword str subscription: The name or ID of a subscription. Set this to acquire tokens for an account other
47
+ than the Azure CLI's current account.
35
48
  :keyword List[str] additionally_allowed_tenants: Specifies tenants in addition to the specified "tenant_id"
36
49
  for which the credential may acquire tokens. Add the wildcard value "*" to allow the credential to
37
50
  acquire tokens for any tenant the application can access.
@@ -51,12 +64,17 @@ class AzureCliCredential(AsyncContextManager):
51
64
  self,
52
65
  *,
53
66
  tenant_id: str = "",
67
+ subscription: Optional[str] = None,
54
68
  additionally_allowed_tenants: Optional[List[str]] = None,
55
69
  process_timeout: int = 10,
56
70
  ) -> None:
57
71
  if tenant_id:
58
72
  validate_tenant_id(tenant_id)
73
+ if subscription:
74
+ validate_subscription(subscription)
75
+
59
76
  self.tenant_id = tenant_id
77
+ self.subscription = subscription
60
78
  self._additionally_allowed_tenants = additionally_allowed_tenants or []
61
79
  self._process_timeout = process_timeout
62
80
 
@@ -131,7 +149,7 @@ class AzureCliCredential(AsyncContextManager):
131
149
  validate_scope(scope)
132
150
 
133
151
  resource = _scopes_to_resource(*scopes)
134
- command = COMMAND_LINE.format(resource)
152
+ command_args = COMMAND_LINE + ["--resource", resource]
135
153
  tenant = resolve_tenant(
136
154
  default_tenant=self.tenant_id,
137
155
  tenant_id=tenant_id,
@@ -140,8 +158,11 @@ class AzureCliCredential(AsyncContextManager):
140
158
  )
141
159
 
142
160
  if tenant:
143
- command += " --tenant " + tenant
144
- output = await _run_command(command, self._process_timeout)
161
+ command_args += ["--tenant", tenant]
162
+
163
+ if self.subscription:
164
+ command_args += ["--subscription", self.subscription]
165
+ output = await _run_command(command_args, self._process_timeout)
145
166
 
146
167
  token = parse_token(output)
147
168
  if not token:
@@ -161,19 +182,16 @@ class AzureCliCredential(AsyncContextManager):
161
182
  """Calling this method is unnecessary"""
162
183
 
163
184
 
164
- async def _run_command(command: str, timeout: int) -> str:
185
+ async def _run_command(command_args: List[str], timeout: int) -> str:
165
186
  # Ensure executable exists in PATH first. This avoids a subprocess call that would fail anyway.
166
- if shutil.which(EXECUTABLE_NAME) is None:
187
+ az_path = shutil.which(EXECUTABLE_NAME)
188
+ if not az_path:
167
189
  raise CredentialUnavailableError(message=CLI_NOT_FOUND)
168
190
 
169
- if sys.platform.startswith("win"):
170
- args = ("cmd", "/c " + command)
171
- else:
172
- args = ("/bin/sh", "-c", command)
173
-
191
+ args = [az_path] + command_args
174
192
  working_directory = get_safe_working_dir()
175
-
176
193
  try:
194
+ _LOGGER.debug("Executing subprocess with the following arguments %s", args)
177
195
  proc = await asyncio.create_subprocess_exec(
178
196
  *args,
179
197
  stdout=asyncio.subprocess.PIPE,
@@ -89,7 +89,7 @@ class DefaultAzureCredential(ChainedTokenCredential):
89
89
  :caption: Create a DefaultAzureCredential.
90
90
  """
91
91
 
92
- def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statements, too-many-locals
92
+ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statements
93
93
  if "tenant_id" in kwargs:
94
94
  raise TypeError("'tenant_id' is not supported in DefaultAzureCredential.")
95
95
 
@@ -145,7 +145,7 @@ class DefaultAzureCredential(ChainedTokenCredential):
145
145
  WorkloadIdentityCredential(
146
146
  client_id=cast(str, client_id),
147
147
  tenant_id=workload_identity_tenant_id,
148
- file=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
148
+ token_file_path=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
149
149
  **kwargs
150
150
  )
151
151
  )
@@ -37,7 +37,7 @@ class ImdsCredential(AsyncContextManager, GetTokenMixin):
37
37
  async def _acquire_token_silently(self, *scopes: str, **kwargs: Any) -> Optional[AccessTokenInfo]:
38
38
  return self._client.get_cached_token(*scopes)
39
39
 
40
- async def _request_token(self, *scopes: str, **kwargs: Any) -> AccessTokenInfo: # pylint:disable=unused-argument
40
+ async def _request_token(self, *scopes: str, **kwargs: Any) -> AccessTokenInfo:
41
41
 
42
42
  if within_credential_chain.get() and not self._endpoint_available:
43
43
  # If within a chain (e.g. DefaultAzureCredential), we do a quick check to see if the IMDS endpoint
@@ -49,7 +49,7 @@ class ImdsCredential(AsyncContextManager, GetTokenMixin):
49
49
  # IMDS responded
50
50
  _check_forbidden_response(ex)
51
51
  self._endpoint_available = True
52
- except Exception as ex: # pylint:disable=broad-except
52
+ except Exception as ex:
53
53
  error_message = (
54
54
  "ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint."
55
55
  )
@@ -78,7 +78,7 @@ class ImdsCredential(AsyncContextManager, GetTokenMixin):
78
78
  _check_forbidden_response(ex)
79
79
  # any other error is unexpected
80
80
  raise ClientAuthenticationError(message=ex.message, response=ex.response) from ex
81
- except Exception as ex: # pylint:disable=broad-except
81
+ except Exception as ex:
82
82
  # if anything else was raised, assume the endpoint is unavailable
83
83
  error_message = "ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint."
84
84
  raise CredentialUnavailableError(error_message) from ex
@@ -96,7 +96,7 @@ class ManagedIdentityCredential(AsyncContextManager):
96
96
  self._credential = WorkloadIdentityCredential(
97
97
  tenant_id=os.environ[EnvironmentVariables.AZURE_TENANT_ID],
98
98
  client_id=workload_client_id,
99
- file=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
99
+ token_file_path=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
100
100
  **kwargs
101
101
  )
102
102
  else:
@@ -21,24 +21,32 @@ def log_get_token_async(fn):
21
21
  try:
22
22
  token = await fn(*args, **kwargs)
23
23
  _LOGGER.log(
24
- logging.DEBUG if within_credential_chain.get() else logging.INFO, "%s succeeded", fn.__qualname__
24
+ logging.DEBUG if within_credential_chain.get() else logging.INFO,
25
+ "%s succeeded",
26
+ fn.__qualname__,
25
27
  )
26
28
  if _LOGGER.isEnabledFor(logging.DEBUG):
27
29
  try:
28
- base64_meta_data = token.token.split(".")[1].encode("utf-8") + b"=="
29
- json_bytes = base64.decodebytes(base64_meta_data)
30
+ base64_meta_data = token.token.split(".")[1]
31
+ padding_needed = -len(base64_meta_data) % 4
32
+ if padding_needed:
33
+ base64_meta_data += "=" * padding_needed
34
+ json_bytes = base64.urlsafe_b64decode(base64_meta_data)
30
35
  json_string = json_bytes.decode("utf-8")
31
36
  json_dict = json.loads(json_string)
32
37
  upn = json_dict.get("upn", "unavailableUpn")
38
+ appid = json_dict.get("appid", "<unavailable>")
39
+ tid = json_dict.get("tid", "<unavailable>")
40
+ oid = json_dict.get("oid", "<unavailable>")
33
41
  log_string = (
34
- "[Authenticated account] Client ID: {}. Tenant ID: {}. User Principal Name: {}. "
35
- "Object ID (user): {}".format(json_dict["appid"], json_dict["tid"], upn, json_dict["oid"])
42
+ f"[Authenticated account] Client ID: {appid}. "
43
+ f"Tenant ID: {tid}. User Principal Name: {upn}. Object ID (user): {oid}"
36
44
  )
37
45
  _LOGGER.debug(log_string)
38
46
  except Exception as ex: # pylint: disable=broad-except
39
47
  _LOGGER.debug("Failed to log the account information: %s", ex, exc_info=True)
40
48
  return token
41
- except Exception as ex: # pylint: disable=broad-except
49
+ except Exception as ex:
42
50
  _LOGGER.log(
43
51
  logging.DEBUG if within_credential_chain.get() else logging.WARNING,
44
52
  "%s failed: %s",
@@ -67,7 +75,7 @@ def wrap_exceptions(fn):
67
75
  return result
68
76
  except ClientAuthenticationError:
69
77
  raise
70
- except Exception as ex: # pylint:disable=broad-except
78
+ except Exception as ex:
71
79
  auth_error = ClientAuthenticationError(message="Authentication failed: {}".format(ex))
72
80
  raise auth_error from ex
73
81
 
@@ -15,7 +15,7 @@ from ..._internal.pipeline import build_async_pipeline
15
15
  T = TypeVar("T", bound="AsyncManagedIdentityClient")
16
16
 
17
17
 
18
- # pylint:disable=async-client-bad-name,missing-client-constructor-parameter-credential
18
+ # pylint:disable=async-client-bad-name
19
19
  class AsyncManagedIdentityClient(AsyncContextManager, ManagedIdentityClientBase):
20
20
  async def __aenter__(self: T) -> T:
21
21
  await self._pipeline.__aenter__()
@@ -10,7 +10,7 @@ __all__ = [
10
10
  "__version__",
11
11
  ]
12
12
 
13
- __version__ = "44.0.0"
13
+ __version__ = "44.0.1"
14
14
 
15
15
 
16
16
  __author__ = "The Python Cryptographic Authority and individual contributors"
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- # Copyright 2024 Google LLC
3
+ # Copyright 2025 Google LLC
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
16
16
 
17
17
  # Generated by the protocol buffer compiler. DO NOT EDIT!
18
18
  # source: google/api/annotations.proto
19
+ # Protobuf Python Version: 4.25.3
19
20
  """Generated protocol buffer code."""
20
21
  from google.protobuf import descriptor as _descriptor
21
22
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -27,9 +28,9 @@ from google.protobuf.internal import builder as _builder
27
28
  _sym_db = _symbol_database.Default()
28
29
 
29
30
 
30
- from google.api import http_pb2 as google_dot_api_dot_http__pb2
31
31
  from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
32
32
 
33
+ from google.api import http_pb2 as google_dot_api_dot_http__pb2
33
34
 
34
35
  DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
35
36
  b'\n\x1cgoogle/api/annotations.proto\x12\ngoogle.api\x1a\x15google/api/http.proto\x1a google/protobuf/descriptor.proto:E\n\x04http\x12\x1e.google.protobuf.MethodOptions\x18\xb0\xca\xbc" \x01(\x0b\x32\x14.google.api.HttpRuleBn\n\x0e\x63om.google.apiB\x10\x41nnotationsProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x04GAPIb\x06proto3'
@@ -41,6 +42,8 @@ _builder.BuildTopDescriptorsAndMessages(
41
42
  DESCRIPTOR, "google.api.annotations_pb2", _globals
42
43
  )
43
44
  if _descriptor._USE_C_DESCRIPTORS == False:
44
- DESCRIPTOR._options = None
45
- DESCRIPTOR._serialized_options = b"\n\016com.google.apiB\020AnnotationsProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI"
45
+ _globals["DESCRIPTOR"]._options = None
46
+ _globals[
47
+ "DESCRIPTOR"
48
+ ]._serialized_options = b"\n\016com.google.apiB\020AnnotationsProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI"
46
49
  # @@protoc_insertion_point(module_scope)
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- # Copyright 2024 Google LLC
3
+ # Copyright 2025 Google LLC
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
16
16
 
17
17
  # Generated by the protocol buffer compiler. DO NOT EDIT!
18
18
  # source: google/api/auth.proto
19
+ # Protobuf Python Version: 4.25.3
19
20
  """Generated protocol buffer code."""
20
21
  from google.protobuf import descriptor as _descriptor
21
22
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -35,8 +36,10 @@ _globals = globals()
35
36
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
36
37
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.auth_pb2", _globals)
37
38
  if _descriptor._USE_C_DESCRIPTORS == False:
38
- DESCRIPTOR._options = None
39
- DESCRIPTOR._serialized_options = b"\n\016com.google.apiB\tAuthProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
39
+ _globals["DESCRIPTOR"]._options = None
40
+ _globals[
41
+ "DESCRIPTOR"
42
+ ]._serialized_options = b"\n\016com.google.apiB\tAuthProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
40
43
  _globals["_AUTHENTICATION"]._serialized_start = 37
41
44
  _globals["_AUTHENTICATION"]._serialized_end = 145
42
45
  _globals["_AUTHENTICATIONRULE"]._serialized_start = 148
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- # Copyright 2024 Google LLC
3
+ # Copyright 2025 Google LLC
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
16
16
 
17
17
  # Generated by the protocol buffer compiler. DO NOT EDIT!
18
18
  # source: google/api/backend.proto
19
+ # Protobuf Python Version: 4.25.3
19
20
  """Generated protocol buffer code."""
20
21
  from google.protobuf import descriptor as _descriptor
21
22
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -35,12 +36,18 @@ _globals = globals()
35
36
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
36
37
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.backend_pb2", _globals)
37
38
  if _descriptor._USE_C_DESCRIPTORS == False:
38
- DESCRIPTOR._options = None
39
- DESCRIPTOR._serialized_options = b"\n\016com.google.apiB\014BackendProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
40
- _BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY._options = None
41
- _BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY._serialized_options = b"8\001"
42
- _BACKENDRULE.fields_by_name["min_deadline"]._options = None
43
- _BACKENDRULE.fields_by_name["min_deadline"]._serialized_options = b"\030\001"
39
+ _globals["DESCRIPTOR"]._options = None
40
+ _globals[
41
+ "DESCRIPTOR"
42
+ ]._serialized_options = b"\n\016com.google.apiB\014BackendProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
43
+ _globals["_BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY"]._options = None
44
+ _globals[
45
+ "_BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY"
46
+ ]._serialized_options = b"8\001"
47
+ _globals["_BACKENDRULE"].fields_by_name["min_deadline"]._options = None
48
+ _globals["_BACKENDRULE"].fields_by_name[
49
+ "min_deadline"
50
+ ]._serialized_options = b"\030\001"
44
51
  _globals["_BACKEND"]._serialized_start = 40
45
52
  _globals["_BACKEND"]._serialized_end = 89
46
53
  _globals["_BACKENDRULE"]._serialized_start = 92