py2docfx 0.1.11rc1981066__py3-none-any.whl → 0.1.11rc1996319__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 (126) hide show
  1. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/authorization_code.py +1 -1
  2. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azd_cli.py +20 -14
  3. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_arc.py +1 -1
  4. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_cli.py +36 -14
  5. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_powershell.py +1 -1
  6. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/chained.py +2 -2
  7. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +4 -3
  8. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +2 -2
  9. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/managed_identity.py +1 -1
  10. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/__init__.py +2 -0
  11. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/auth_code_redirect_handler.py +1 -1
  12. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/decorators.py +15 -7
  13. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +1 -1
  14. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/managed_identity_client.py +0 -1
  15. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_client.py +1 -1
  16. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_managed_identity_client.py +2 -1
  17. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/shared_token_cache.py +3 -3
  18. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/utils.py +17 -2
  19. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
  20. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azd_cli.py +14 -11
  21. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_cli.py +30 -12
  22. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +2 -2
  23. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +3 -3
  24. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/managed_identity.py +1 -1
  25. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/decorators.py +15 -7
  26. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/managed_identity_client.py +1 -1
  27. py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
  28. py2docfx/venv/venv1/Lib/site-packages/google/api/annotations_pb2.py +7 -4
  29. py2docfx/venv/venv1/Lib/site-packages/google/api/auth_pb2.py +6 -3
  30. py2docfx/venv/venv1/Lib/site-packages/google/api/backend_pb2.py +14 -7
  31. py2docfx/venv/venv1/Lib/site-packages/google/api/billing_pb2.py +6 -3
  32. py2docfx/venv/venv1/Lib/site-packages/google/api/client_pb2.py +47 -38
  33. py2docfx/venv/venv1/Lib/site-packages/google/api/config_change_pb2.py +6 -3
  34. py2docfx/venv/venv1/Lib/site-packages/google/api/consumer_pb2.py +6 -3
  35. py2docfx/venv/venv1/Lib/site-packages/google/api/context_pb2.py +6 -3
  36. py2docfx/venv/venv1/Lib/site-packages/google/api/control_pb2.py +6 -4
  37. py2docfx/venv/venv1/Lib/site-packages/google/api/distribution_pb2.py +7 -5
  38. py2docfx/venv/venv1/Lib/site-packages/google/api/documentation_pb2.py +6 -3
  39. py2docfx/venv/venv1/Lib/site-packages/google/api/endpoint_pb2.py +6 -3
  40. py2docfx/venv/venv1/Lib/site-packages/google/api/error_reason_pb2.py +6 -3
  41. py2docfx/venv/venv1/Lib/site-packages/google/api/field_behavior_pb2.py +8 -6
  42. py2docfx/venv/venv1/Lib/site-packages/google/api/field_info_pb2.py +6 -4
  43. py2docfx/venv/venv1/Lib/site-packages/google/api/http_pb2.py +7 -4
  44. py2docfx/venv/venv1/Lib/site-packages/google/api/httpbody_pb2.py +6 -4
  45. py2docfx/venv/venv1/Lib/site-packages/google/api/label_pb2.py +7 -4
  46. py2docfx/venv/venv1/Lib/site-packages/google/api/launch_stage_pb2.py +6 -3
  47. py2docfx/venv/venv1/Lib/site-packages/google/api/log_pb2.py +6 -4
  48. py2docfx/venv/venv1/Lib/site-packages/google/api/logging_pb2.py +6 -3
  49. py2docfx/venv/venv1/Lib/site-packages/google/api/metric_pb2.py +12 -9
  50. py2docfx/venv/venv1/Lib/site-packages/google/api/monitored_resource_pb2.py +15 -10
  51. py2docfx/venv/venv1/Lib/site-packages/google/api/monitoring_pb2.py +6 -3
  52. py2docfx/venv/venv1/Lib/site-packages/google/api/policy_pb2.py +7 -5
  53. py2docfx/venv/venv1/Lib/site-packages/google/api/quota_pb2.py +10 -7
  54. py2docfx/venv/venv1/Lib/site-packages/google/api/resource_pb2.py +7 -5
  55. py2docfx/venv/venv1/Lib/site-packages/google/api/routing_pb2.py +6 -4
  56. py2docfx/venv/venv1/Lib/site-packages/google/api/service_pb2.py +15 -12
  57. py2docfx/venv/venv1/Lib/site-packages/google/api/source_info_pb2.py +6 -4
  58. py2docfx/venv/venv1/Lib/site-packages/google/api/system_parameter_pb2.py +6 -3
  59. py2docfx/venv/venv1/Lib/site-packages/google/api/usage_pb2.py +6 -3
  60. py2docfx/venv/venv1/Lib/site-packages/google/api/visibility_pb2.py +7 -5
  61. py2docfx/venv/venv1/Lib/site-packages/google/cloud/extended_operations_pb2.py +6 -4
  62. py2docfx/venv/venv1/Lib/site-packages/google/cloud/location/locations_pb2.py +18 -13
  63. py2docfx/venv/venv1/Lib/site-packages/google/gapic/metadata/gapic_metadata_pb2.py +31 -26
  64. py2docfx/venv/venv1/Lib/site-packages/google/logging/type/http_request_pb2.py +6 -4
  65. py2docfx/venv/venv1/Lib/site-packages/google/logging/type/log_severity_pb2.py +6 -3
  66. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc.py +2 -1
  67. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc_pb2.py +11 -10
  68. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2.py +20 -17
  69. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2_grpc.py +1 -2
  70. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto.py +2 -1
  71. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto_pb2.py +22 -19
  72. py2docfx/venv/venv1/Lib/site-packages/google/rpc/code_pb2.py +6 -3
  73. py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/attribute_context_pb2.py +20 -16
  74. py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/audit_context_pb2.py +7 -5
  75. py2docfx/venv/venv1/Lib/site-packages/google/rpc/error_details_pb2.py +21 -19
  76. py2docfx/venv/venv1/Lib/site-packages/google/rpc/http_pb2.py +6 -3
  77. py2docfx/venv/venv1/Lib/site-packages/google/rpc/status_pb2.py +6 -4
  78. py2docfx/venv/venv1/Lib/site-packages/google/type/calendar_period_pb2.py +6 -3
  79. py2docfx/venv/venv1/Lib/site-packages/google/type/color_pb2.py +6 -4
  80. py2docfx/venv/venv1/Lib/site-packages/google/type/date_pb2.py +6 -3
  81. py2docfx/venv/venv1/Lib/site-packages/google/type/datetime_pb2.py +6 -4
  82. py2docfx/venv/venv1/Lib/site-packages/google/type/dayofweek_pb2.py +6 -3
  83. py2docfx/venv/venv1/Lib/site-packages/google/type/decimal_pb2.py +6 -3
  84. py2docfx/venv/venv1/Lib/site-packages/google/type/expr_pb2.py +6 -3
  85. py2docfx/venv/venv1/Lib/site-packages/google/type/fraction_pb2.py +6 -3
  86. py2docfx/venv/venv1/Lib/site-packages/google/type/interval_pb2.py +6 -4
  87. py2docfx/venv/venv1/Lib/site-packages/google/type/latlng_pb2.py +6 -3
  88. py2docfx/venv/venv1/Lib/site-packages/google/type/localized_text_pb2.py +6 -3
  89. py2docfx/venv/venv1/Lib/site-packages/google/type/money_pb2.py +6 -3
  90. py2docfx/venv/venv1/Lib/site-packages/google/type/month_pb2.py +6 -3
  91. py2docfx/venv/venv1/Lib/site-packages/google/type/phone_number_pb2.py +6 -3
  92. py2docfx/venv/venv1/Lib/site-packages/google/type/postal_address_pb2.py +6 -3
  93. py2docfx/venv/venv1/Lib/site-packages/google/type/quaternion_pb2.py +6 -3
  94. py2docfx/venv/venv1/Lib/site-packages/google/type/timeofday_pb2.py +6 -3
  95. py2docfx/venv/venv1/Lib/site-packages/psutil/__init__.py +122 -201
  96. py2docfx/venv/venv1/Lib/site-packages/psutil/_common.py +84 -128
  97. py2docfx/venv/venv1/Lib/site-packages/psutil/_psaix.py +24 -38
  98. py2docfx/venv/venv1/Lib/site-packages/psutil/_psbsd.py +44 -58
  99. py2docfx/venv/venv1/Lib/site-packages/psutil/_pslinux.py +170 -254
  100. py2docfx/venv/venv1/Lib/site-packages/psutil/_psosx.py +8 -16
  101. py2docfx/venv/venv1/Lib/site-packages/psutil/_psposix.py +13 -49
  102. py2docfx/venv/venv1/Lib/site-packages/psutil/_pssunos.py +41 -60
  103. py2docfx/venv/venv1/Lib/site-packages/psutil/_pswindows.py +75 -145
  104. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__init__.py +105 -193
  105. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_aix.py +2 -2
  106. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_bsd.py +27 -26
  107. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_connections.py +16 -17
  108. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_contracts.py +5 -19
  109. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_linux.py +153 -211
  110. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_memleaks.py +0 -6
  111. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_misc.py +22 -207
  112. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_osx.py +9 -4
  113. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_posix.py +8 -15
  114. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process.py +104 -184
  115. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process_all.py +28 -36
  116. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_scripts.py +240 -0
  117. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_sunos.py +1 -1
  118. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_system.py +44 -50
  119. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_testutils.py +23 -33
  120. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_unicode.py +8 -67
  121. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_windows.py +32 -52
  122. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1996319.dist-info}/METADATA +1 -1
  123. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1996319.dist-info}/RECORD +125 -125
  124. py2docfx/venv/venv1/Lib/site-packages/psutil/_compat.py +0 -477
  125. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1996319.dist-info}/WHEEL +0 -0
  126. {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1996319.dist-info}/top_level.txt +0 -0
@@ -85,7 +85,7 @@ class AuthorizationCodeCredential(GetTokenMixin):
85
85
  attribute gives a reason. Any error response from Microsoft Entra ID is available as the error's
86
86
  ``response`` attribute.
87
87
  """
88
- # pylint:disable=useless-super-delegation
88
+
89
89
  return super(AuthorizationCodeCredential, self).get_token(
90
90
  *scopes, claims=claims, tenant_id=tenant_id, client_secret=self._client_secret, **kwargs
91
91
  )
@@ -5,6 +5,7 @@
5
5
 
6
6
  from datetime import datetime
7
7
  import json
8
+ import logging
8
9
  import os
9
10
  import re
10
11
  import shutil
@@ -19,12 +20,15 @@ from .. import CredentialUnavailableError
19
20
  from .._internal import resolve_tenant, within_dac, validate_tenant_id, validate_scope
20
21
  from .._internal.decorators import log_get_token
21
22
 
23
+
24
+ _LOGGER = logging.getLogger(__name__)
25
+
22
26
  CLI_NOT_FOUND = (
23
27
  "Azure Developer CLI could not be found. "
24
28
  "Please visit https://aka.ms/azure-dev for installation instructions and then,"
25
29
  "once installed, authenticate to your Azure account using 'azd auth login'."
26
30
  )
27
- COMMAND_LINE = "azd auth token --output json --scope {}"
31
+ COMMAND_LINE = ["auth", "token", "--output", "json"]
28
32
  EXECUTABLE_NAME = "azd"
29
33
  NOT_LOGGED_IN = "Please run 'azd auth login' from a command prompt to authenticate before using this credential."
30
34
 
@@ -160,8 +164,9 @@ class AzureDeveloperCliCredential:
160
164
  for scope in scopes:
161
165
  validate_scope(scope)
162
166
 
163
- commandString = " --scope ".join(scopes)
164
- command = COMMAND_LINE.format(commandString)
167
+ command_args = COMMAND_LINE.copy()
168
+ for scope in scopes:
169
+ command_args += ["--scope", scope]
165
170
  tenant = resolve_tenant(
166
171
  default_tenant=self.tenant_id,
167
172
  tenant_id=tenant_id,
@@ -169,8 +174,8 @@ class AzureDeveloperCliCredential:
169
174
  **kwargs,
170
175
  )
171
176
  if tenant:
172
- command += " --tenant-id " + tenant
173
- output = _run_command(command, self._process_timeout)
177
+ command_args += ["--tenant-id", tenant]
178
+ output = _run_command(command_args, self._process_timeout)
174
179
 
175
180
  token = parse_token(output)
176
181
  if not token:
@@ -236,15 +241,13 @@ def sanitize_output(output: str) -> str:
236
241
  return re.sub(r"\"token\": \"(.*?)(\"|$)", "****", output)
237
242
 
238
243
 
239
- def _run_command(command: str, timeout: int) -> str:
244
+ def _run_command(command_args: List[str], timeout: int) -> str:
240
245
  # Ensure executable exists in PATH first. This avoids a subprocess call that would fail anyway.
241
- if shutil.which(EXECUTABLE_NAME) is None:
246
+ azd_path = shutil.which(EXECUTABLE_NAME)
247
+ if not azd_path:
242
248
  raise CredentialUnavailableError(message=CLI_NOT_FOUND)
243
249
 
244
- if sys.platform.startswith("win"):
245
- args = ["cmd", "/c", command]
246
- else:
247
- args = ["/bin/sh", "-c", command]
250
+ args = [azd_path] + command_args
248
251
  try:
249
252
  working_directory = get_safe_working_dir()
250
253
 
@@ -257,13 +260,16 @@ def _run_command(command: str, timeout: int) -> str:
257
260
  "timeout": timeout,
258
261
  }
259
262
 
263
+ _LOGGER.debug("Executing subprocess with the following arguments %s", args)
260
264
  return subprocess.check_output(args, **kwargs)
261
265
  except subprocess.CalledProcessError as ex:
262
266
  # non-zero return from shell
263
267
  # Fallback check in case the executable is not found while executing subprocess.
264
- if ex.returncode == 127 or ex.stderr.startswith("'azd' is not recognized"):
268
+ if ex.returncode == 127 or (ex.stderr is not None and ex.stderr.startswith("'azd' is not recognized")):
265
269
  raise CredentialUnavailableError(message=CLI_NOT_FOUND) from ex
266
- if "not logged in, run `azd auth login` to login" in ex.stderr and "AADSTS" not in ex.stderr:
270
+ if ex.stderr is not None and (
271
+ "not logged in, run `azd auth login` to login" in ex.stderr and "AADSTS" not in ex.stderr
272
+ ):
267
273
  raise CredentialUnavailableError(message=NOT_LOGGED_IN) from ex
268
274
 
269
275
  # return code is from the CLI -> propagate its output
@@ -278,7 +284,7 @@ def _run_command(command: str, timeout: int) -> str:
278
284
  # failed to execute 'cmd' or '/bin/sh'
279
285
  error = CredentialUnavailableError(message="Failed to execute '{}'".format(args[0]))
280
286
  raise error from ex
281
- except Exception as ex: # pylint:disable=broad-except
287
+ except Exception as ex:
282
288
  # could be a timeout, for example
283
289
  error = CredentialUnavailableError(message="Failed to invoke the Azure Developer CLI")
284
290
  raise error from ex
@@ -54,7 +54,7 @@ def _get_secret_key(response: PipelineResponse) -> str:
54
54
  with open(key_file, "r", encoding="utf-8") as file:
55
55
  try:
56
56
  return file.read()
57
- except Exception as error: # pylint:disable=broad-except
57
+ except Exception as error:
58
58
  # user is expected to have obtained read permission prior to this being called
59
59
  raise ClientAuthenticationError(
60
60
  message="Could not read file {} contents: {}".format(key_file, error)
@@ -6,6 +6,7 @@ from datetime import datetime
6
6
  import json
7
7
  import os
8
8
  import re
9
+ import logging
9
10
  import shutil
10
11
  import subprocess
11
12
  import sys
@@ -15,12 +16,22 @@ from azure.core.credentials import AccessToken, AccessTokenInfo, TokenRequestOpt
15
16
  from azure.core.exceptions import ClientAuthenticationError
16
17
 
17
18
  from .. import CredentialUnavailableError
18
- from .._internal import _scopes_to_resource, resolve_tenant, within_dac, validate_tenant_id, validate_scope
19
+ from .._internal import (
20
+ _scopes_to_resource,
21
+ resolve_tenant,
22
+ within_dac,
23
+ validate_tenant_id,
24
+ validate_scope,
25
+ validate_subscription,
26
+ )
19
27
  from .._internal.decorators import log_get_token
20
28
 
21
29
 
30
+ _LOGGER = logging.getLogger(__name__)
31
+
22
32
  CLI_NOT_FOUND = "Azure CLI not found on path"
23
- COMMAND_LINE = "az account get-access-token --output json --resource {}"
33
+ # COMMAND_LINE = "account get-access-token --output json --resource {}"
34
+ COMMAND_LINE = ["account", "get-access-token", "--output", "json"]
24
35
  EXECUTABLE_NAME = "az"
25
36
  NOT_LOGGED_IN = "Please run 'az login' to set up an account"
26
37
 
@@ -31,6 +42,8 @@ class AzureCliCredential:
31
42
  This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity.
32
43
 
33
44
  :keyword str tenant_id: Optional tenant to include in the token request.
45
+ :keyword str subscription: The name or ID of a subscription. Set this to acquire tokens for an account other
46
+ than the Azure CLI's current account.
34
47
  :keyword List[str] additionally_allowed_tenants: Specifies tenants in addition to the specified "tenant_id"
35
48
  for which the credential may acquire tokens. Add the wildcard value "*" to allow the credential to
36
49
  acquire tokens for any tenant the application can access.
@@ -50,12 +63,17 @@ class AzureCliCredential:
50
63
  self,
51
64
  *,
52
65
  tenant_id: str = "",
66
+ subscription: Optional[str] = None,
53
67
  additionally_allowed_tenants: Optional[List[str]] = None,
54
68
  process_timeout: int = 10,
55
69
  ) -> None:
56
70
  if tenant_id:
57
71
  validate_tenant_id(tenant_id)
72
+ if subscription:
73
+ validate_subscription(subscription)
74
+
58
75
  self.tenant_id = tenant_id
76
+ self.subscription = subscription
59
77
  self._additionally_allowed_tenants = additionally_allowed_tenants or []
60
78
  self._process_timeout = process_timeout
61
79
 
@@ -135,7 +153,7 @@ class AzureCliCredential:
135
153
  validate_scope(scope)
136
154
 
137
155
  resource = _scopes_to_resource(*scopes)
138
- command = COMMAND_LINE.format(resource)
156
+ command_args = COMMAND_LINE + ["--resource", resource]
139
157
  tenant = resolve_tenant(
140
158
  default_tenant=self.tenant_id,
141
159
  tenant_id=tenant_id,
@@ -143,8 +161,11 @@ class AzureCliCredential:
143
161
  **kwargs,
144
162
  )
145
163
  if tenant:
146
- command += " --tenant " + tenant
147
- output = _run_command(command, self._process_timeout)
164
+ command_args += ["--tenant", tenant]
165
+
166
+ if self.subscription:
167
+ command_args += ["--subscription", self.subscription]
168
+ output = _run_command(command_args, self._process_timeout)
148
169
 
149
170
  token = parse_token(output)
150
171
  if not token:
@@ -211,15 +232,13 @@ def sanitize_output(output: str) -> str:
211
232
  return re.sub(r"\"accessToken\": \"(.*?)(\"|$)", "****", output)
212
233
 
213
234
 
214
- def _run_command(command: str, timeout: int) -> str:
235
+ def _run_command(command_args: List[str], timeout: int) -> str:
215
236
  # Ensure executable exists in PATH first. This avoids a subprocess call that would fail anyway.
216
- if shutil.which(EXECUTABLE_NAME) is None:
237
+ az_path = shutil.which(EXECUTABLE_NAME)
238
+ if not az_path:
217
239
  raise CredentialUnavailableError(message=CLI_NOT_FOUND)
218
240
 
219
- if sys.platform.startswith("win"):
220
- args = ["cmd", "/c", command]
221
- else:
222
- args = ["/bin/sh", "-c", command]
241
+ args = [az_path] + command_args
223
242
  try:
224
243
  working_directory = get_safe_working_dir()
225
244
 
@@ -231,13 +250,16 @@ def _run_command(command: str, timeout: int) -> str:
231
250
  "timeout": timeout,
232
251
  "env": dict(os.environ, AZURE_CORE_NO_COLOR="true"),
233
252
  }
253
+ _LOGGER.debug("Executing subprocess with the following arguments %s", args)
234
254
  return subprocess.check_output(args, **kwargs)
235
255
  except subprocess.CalledProcessError as ex:
236
256
  # non-zero return from shell
237
257
  # Fallback check in case the executable is not found while executing subprocess.
238
- if ex.returncode == 127 or ex.stderr.startswith("'az' is not recognized"):
258
+ if ex.returncode == 127 or (ex.stderr is not None and ex.stderr.startswith("'az' is not recognized")):
239
259
  raise CredentialUnavailableError(message=CLI_NOT_FOUND) from ex
240
- if ("az login" in ex.stderr or "az account set" in ex.stderr) and "AADSTS" not in ex.stderr:
260
+ if ex.stderr is not None and (
261
+ ("az login" in ex.stderr or "az account set" in ex.stderr) and "AADSTS" not in ex.stderr
262
+ ):
241
263
  raise CredentialUnavailableError(message=NOT_LOGGED_IN) from ex
242
264
 
243
265
  # return code is from the CLI -> propagate its output
@@ -252,7 +274,7 @@ def _run_command(command: str, timeout: int) -> str:
252
274
  # failed to execute 'cmd' or '/bin/sh'
253
275
  error = CredentialUnavailableError(message="Failed to execute '{}'".format(args[0]))
254
276
  raise error from ex
255
- except Exception as ex: # pylint:disable=broad-except
277
+ except Exception as ex:
256
278
  # could be a timeout, for example
257
279
  error = CredentialUnavailableError(message="Failed to invoke the Azure CLI")
258
280
  raise error from ex
@@ -192,7 +192,7 @@ def run_command_line(command_line: List[str], timeout: int) -> str:
192
192
  proc = start_process(command_line)
193
193
  stdout, stderr = proc.communicate(**kwargs)
194
194
 
195
- except Exception as ex: # pylint:disable=broad-except
195
+ except Exception as ex:
196
196
  # failed to execute "cmd" or "/bin/sh", or timed out; PowerShell and Az.Account may or may not be installed
197
197
  # (handling Exception here because subprocess.SubprocessError and .TimeoutExpired were added in 3.3)
198
198
  if proc and not proc.returncode:
@@ -37,8 +37,8 @@ class ChainedTokenCredential:
37
37
  """A sequence of credentials that is itself a credential.
38
38
 
39
39
  Its :func:`get_token` method calls ``get_token`` on each credential in the sequence, in order, returning the first
40
- valid token received. For more information, see
41
- https://aka.ms/azsdk/python/identity/credential-chains#chainedtokencredential-overview.
40
+ valid token received. For more information, see `ChainedTokenCredential overview
41
+ <"https://aka.ms/azsdk/python/identity/credential-chains#chainedtokencredential-overview">`__.
42
42
 
43
43
  :param credentials: credential instances to form the chain
44
44
  :type credentials: ~azure.core.credentials.TokenCredential
@@ -24,8 +24,9 @@ _LOGGER = logging.getLogger(__name__)
24
24
 
25
25
 
26
26
  class DefaultAzureCredential(ChainedTokenCredential):
27
- """A credential capable of handling most Azure SDK authentication scenarios. See
28
- https://aka.ms/azsdk/python/identity/credential-chains#usage-guidance-for-defaultazurecredential.
27
+ """A credential capable of handling most Azure SDK authentication scenarios. For more information, See
28
+ `Usage guidance for DefaultAzureCredential
29
+ <"https://aka.ms/azsdk/python/identity/credential-chains#usage-guidance-for-defaultazurecredential">`__.
29
30
 
30
31
  The identity it uses depends on the environment. When an access token is needed, it requests one using these
31
32
  identities in turn, stopping when one provides a token:
@@ -153,7 +154,7 @@ class DefaultAzureCredential(ChainedTokenCredential):
153
154
  WorkloadIdentityCredential(
154
155
  client_id=cast(str, client_id),
155
156
  tenant_id=workload_identity_tenant_id,
156
- file=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
157
+ token_file_path=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
157
158
  **kwargs
158
159
  )
159
160
  )
@@ -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,