py2docfx 0.1.11.dev1987375__py3-none-any.whl → 0.1.11.dev1994698__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 (137) hide show
  1. py2docfx/__main__.py +8 -5
  2. py2docfx/convert_prepare/generate_document.py +3 -3
  3. py2docfx/convert_prepare/get_source.py +1 -1
  4. py2docfx/convert_prepare/git.py +1 -1
  5. py2docfx/convert_prepare/package_info.py +3 -3
  6. py2docfx/convert_prepare/post_process/merge_toc.py +3 -2
  7. py2docfx/convert_prepare/sphinx_caller.py +20 -6
  8. py2docfx/convert_prepare/tests/test_environment.py +0 -1
  9. py2docfx/convert_prepare/tests/test_generate_document.py +4 -2
  10. py2docfx/convert_prepare/tests/test_sphinx_caller.py +4 -3
  11. py2docfx/docfx_yaml/logger.py +8 -13
  12. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/authorization_code.py +1 -1
  13. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azd_cli.py +20 -14
  14. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_arc.py +1 -1
  15. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_cli.py +36 -14
  16. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_powershell.py +1 -1
  17. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/chained.py +2 -2
  18. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +4 -3
  19. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +2 -2
  20. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/managed_identity.py +1 -1
  21. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/__init__.py +2 -0
  22. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/auth_code_redirect_handler.py +1 -1
  23. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/decorators.py +15 -7
  24. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +1 -1
  25. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/managed_identity_client.py +0 -1
  26. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_client.py +1 -1
  27. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_managed_identity_client.py +2 -1
  28. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/shared_token_cache.py +3 -3
  29. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/utils.py +17 -2
  30. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
  31. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azd_cli.py +14 -11
  32. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_cli.py +30 -12
  33. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +2 -2
  34. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +3 -3
  35. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/managed_identity.py +1 -1
  36. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/decorators.py +15 -7
  37. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/managed_identity_client.py +1 -1
  38. py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
  39. py2docfx/venv/venv1/Lib/site-packages/google/api/annotations_pb2.py +7 -4
  40. py2docfx/venv/venv1/Lib/site-packages/google/api/auth_pb2.py +6 -3
  41. py2docfx/venv/venv1/Lib/site-packages/google/api/backend_pb2.py +14 -7
  42. py2docfx/venv/venv1/Lib/site-packages/google/api/billing_pb2.py +6 -3
  43. py2docfx/venv/venv1/Lib/site-packages/google/api/client_pb2.py +47 -38
  44. py2docfx/venv/venv1/Lib/site-packages/google/api/config_change_pb2.py +6 -3
  45. py2docfx/venv/venv1/Lib/site-packages/google/api/consumer_pb2.py +6 -3
  46. py2docfx/venv/venv1/Lib/site-packages/google/api/context_pb2.py +6 -3
  47. py2docfx/venv/venv1/Lib/site-packages/google/api/control_pb2.py +6 -4
  48. py2docfx/venv/venv1/Lib/site-packages/google/api/distribution_pb2.py +7 -5
  49. py2docfx/venv/venv1/Lib/site-packages/google/api/documentation_pb2.py +6 -3
  50. py2docfx/venv/venv1/Lib/site-packages/google/api/endpoint_pb2.py +6 -3
  51. py2docfx/venv/venv1/Lib/site-packages/google/api/error_reason_pb2.py +6 -3
  52. py2docfx/venv/venv1/Lib/site-packages/google/api/field_behavior_pb2.py +8 -6
  53. py2docfx/venv/venv1/Lib/site-packages/google/api/field_info_pb2.py +6 -4
  54. py2docfx/venv/venv1/Lib/site-packages/google/api/http_pb2.py +7 -4
  55. py2docfx/venv/venv1/Lib/site-packages/google/api/httpbody_pb2.py +6 -4
  56. py2docfx/venv/venv1/Lib/site-packages/google/api/label_pb2.py +7 -4
  57. py2docfx/venv/venv1/Lib/site-packages/google/api/launch_stage_pb2.py +6 -3
  58. py2docfx/venv/venv1/Lib/site-packages/google/api/log_pb2.py +6 -4
  59. py2docfx/venv/venv1/Lib/site-packages/google/api/logging_pb2.py +6 -3
  60. py2docfx/venv/venv1/Lib/site-packages/google/api/metric_pb2.py +12 -9
  61. py2docfx/venv/venv1/Lib/site-packages/google/api/monitored_resource_pb2.py +15 -10
  62. py2docfx/venv/venv1/Lib/site-packages/google/api/monitoring_pb2.py +6 -3
  63. py2docfx/venv/venv1/Lib/site-packages/google/api/policy_pb2.py +7 -5
  64. py2docfx/venv/venv1/Lib/site-packages/google/api/quota_pb2.py +10 -7
  65. py2docfx/venv/venv1/Lib/site-packages/google/api/resource_pb2.py +7 -5
  66. py2docfx/venv/venv1/Lib/site-packages/google/api/routing_pb2.py +6 -4
  67. py2docfx/venv/venv1/Lib/site-packages/google/api/service_pb2.py +15 -12
  68. py2docfx/venv/venv1/Lib/site-packages/google/api/source_info_pb2.py +6 -4
  69. py2docfx/venv/venv1/Lib/site-packages/google/api/system_parameter_pb2.py +6 -3
  70. py2docfx/venv/venv1/Lib/site-packages/google/api/usage_pb2.py +6 -3
  71. py2docfx/venv/venv1/Lib/site-packages/google/api/visibility_pb2.py +7 -5
  72. py2docfx/venv/venv1/Lib/site-packages/google/cloud/extended_operations_pb2.py +6 -4
  73. py2docfx/venv/venv1/Lib/site-packages/google/cloud/location/locations_pb2.py +18 -13
  74. py2docfx/venv/venv1/Lib/site-packages/google/gapic/metadata/gapic_metadata_pb2.py +31 -26
  75. py2docfx/venv/venv1/Lib/site-packages/google/logging/type/http_request_pb2.py +6 -4
  76. py2docfx/venv/venv1/Lib/site-packages/google/logging/type/log_severity_pb2.py +6 -3
  77. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc.py +2 -1
  78. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc_pb2.py +11 -10
  79. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2.py +20 -17
  80. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2_grpc.py +1 -2
  81. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto.py +2 -1
  82. py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto_pb2.py +22 -19
  83. py2docfx/venv/venv1/Lib/site-packages/google/rpc/code_pb2.py +6 -3
  84. py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/attribute_context_pb2.py +20 -16
  85. py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/audit_context_pb2.py +7 -5
  86. py2docfx/venv/venv1/Lib/site-packages/google/rpc/error_details_pb2.py +21 -19
  87. py2docfx/venv/venv1/Lib/site-packages/google/rpc/http_pb2.py +6 -3
  88. py2docfx/venv/venv1/Lib/site-packages/google/rpc/status_pb2.py +6 -4
  89. py2docfx/venv/venv1/Lib/site-packages/google/type/calendar_period_pb2.py +6 -3
  90. py2docfx/venv/venv1/Lib/site-packages/google/type/color_pb2.py +6 -4
  91. py2docfx/venv/venv1/Lib/site-packages/google/type/date_pb2.py +6 -3
  92. py2docfx/venv/venv1/Lib/site-packages/google/type/datetime_pb2.py +6 -4
  93. py2docfx/venv/venv1/Lib/site-packages/google/type/dayofweek_pb2.py +6 -3
  94. py2docfx/venv/venv1/Lib/site-packages/google/type/decimal_pb2.py +6 -3
  95. py2docfx/venv/venv1/Lib/site-packages/google/type/expr_pb2.py +6 -3
  96. py2docfx/venv/venv1/Lib/site-packages/google/type/fraction_pb2.py +6 -3
  97. py2docfx/venv/venv1/Lib/site-packages/google/type/interval_pb2.py +6 -4
  98. py2docfx/venv/venv1/Lib/site-packages/google/type/latlng_pb2.py +6 -3
  99. py2docfx/venv/venv1/Lib/site-packages/google/type/localized_text_pb2.py +6 -3
  100. py2docfx/venv/venv1/Lib/site-packages/google/type/money_pb2.py +6 -3
  101. py2docfx/venv/venv1/Lib/site-packages/google/type/month_pb2.py +6 -3
  102. py2docfx/venv/venv1/Lib/site-packages/google/type/phone_number_pb2.py +6 -3
  103. py2docfx/venv/venv1/Lib/site-packages/google/type/postal_address_pb2.py +6 -3
  104. py2docfx/venv/venv1/Lib/site-packages/google/type/quaternion_pb2.py +6 -3
  105. py2docfx/venv/venv1/Lib/site-packages/google/type/timeofday_pb2.py +6 -3
  106. py2docfx/venv/venv1/Lib/site-packages/psutil/__init__.py +122 -201
  107. py2docfx/venv/venv1/Lib/site-packages/psutil/_common.py +84 -128
  108. py2docfx/venv/venv1/Lib/site-packages/psutil/_psaix.py +24 -38
  109. py2docfx/venv/venv1/Lib/site-packages/psutil/_psbsd.py +44 -58
  110. py2docfx/venv/venv1/Lib/site-packages/psutil/_pslinux.py +170 -254
  111. py2docfx/venv/venv1/Lib/site-packages/psutil/_psosx.py +8 -16
  112. py2docfx/venv/venv1/Lib/site-packages/psutil/_psposix.py +13 -49
  113. py2docfx/venv/venv1/Lib/site-packages/psutil/_pssunos.py +41 -60
  114. py2docfx/venv/venv1/Lib/site-packages/psutil/_pswindows.py +75 -145
  115. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__init__.py +105 -193
  116. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_aix.py +2 -2
  117. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_bsd.py +27 -26
  118. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_connections.py +16 -17
  119. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_contracts.py +5 -19
  120. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_linux.py +153 -211
  121. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_memleaks.py +0 -6
  122. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_misc.py +22 -207
  123. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_osx.py +9 -4
  124. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_posix.py +8 -15
  125. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process.py +104 -184
  126. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process_all.py +28 -36
  127. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_scripts.py +240 -0
  128. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_sunos.py +1 -1
  129. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_system.py +44 -50
  130. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_testutils.py +23 -33
  131. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_unicode.py +8 -67
  132. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_windows.py +32 -52
  133. {py2docfx-0.1.11.dev1987375.dist-info → py2docfx-0.1.11.dev1994698.dist-info}/METADATA +1 -1
  134. {py2docfx-0.1.11.dev1987375.dist-info → py2docfx-0.1.11.dev1994698.dist-info}/RECORD +136 -136
  135. py2docfx/venv/venv1/Lib/site-packages/psutil/_compat.py +0 -477
  136. {py2docfx-0.1.11.dev1987375.dist-info → py2docfx-0.1.11.dev1994698.dist-info}/WHEEL +0 -0
  137. {py2docfx-0.1.11.dev1987375.dist-info → py2docfx-0.1.11.dev1994698.dist-info}/top_level.txt +0 -0
py2docfx/__main__.py CHANGED
@@ -36,7 +36,6 @@ async def donwload_package_generate_documents(
36
36
  py2docfxEnvironment.prepare_base_venv(required_package_list, github_token, ado_token))
37
37
 
38
38
  for idx, package in enumerate(package_info_list):
39
- os.environ['PROCESSING_PACKAGE_NAME'] = package.name
40
39
  package_number = start_num + idx
41
40
  py2docfx_logger = py2docfxLogger.get_logger(__name__)
42
41
  msg = f"Processing package {package.name}, env_prepare_tasks: {len(env_prepare_tasks)}"
@@ -47,9 +46,9 @@ async def donwload_package_generate_documents(
47
46
  except Exception as e:
48
47
  msg = f"Failed to setup venv for package {package.name}: {e}"
49
48
  py2docfx_logger.error(msg)
50
- raise
49
+ raise e
51
50
 
52
- generate_document(package, output_root,
51
+ await generate_document(package, output_root,
53
52
  py2docfxEnvironment.get_base_venv_sphinx_build_path(),
54
53
  py2docfxEnvironment.get_venv_package_path(idx),
55
54
  py2docfxEnvironment.get_base_venv_exe())
@@ -101,10 +100,15 @@ def main(argv) -> int:
101
100
  github_token, ado_token,
102
101
  output_root, verbose,
103
102
  show_warning) = parse_command_line_args(argv)
104
-
103
+
105
104
  clean_up_folder_list = [py2docfxEnvironment.VENV_DIR, DIST_TEMP, SOURCE_REPO, TARGET_REPO, LOG_FOLDER]
106
105
  temp_folder_clean_up(clean_up_folder_list)
107
106
 
107
+ # create log folder and package log folder
108
+ log_folder = os.path.join(PACKAGE_ROOT, LOG_FOLDER)
109
+ os.makedirs(log_folder)
110
+ os.makedirs(os.path.join(log_folder, "package_logs"))
111
+
108
112
  py2docfxLogger.decide_global_log_level(verbose, show_warning)
109
113
 
110
114
  py2docfx_logger = py2docfxLogger.get_logger(__name__)
@@ -123,7 +127,6 @@ def main(argv) -> int:
123
127
  msg = f"An error occurred: {e}"
124
128
  py2docfx_logger.error(msg)
125
129
  fishish_up()
126
- # asyncio.get_event_loop().stop()
127
130
  raise
128
131
 
129
132
  fishish_up()
@@ -10,7 +10,7 @@ from py2docfx.convert_prepare.subpackage import merge_subpackage_files
10
10
 
11
11
  CONF_TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "conf_templates")
12
12
 
13
- def generate_document(pkg: PackageInfo, output_root: str | os.PathLike, sphinx_build_path: str, extra_package_path: str, executable=sys.executable):
13
+ async def generate_document(pkg: PackageInfo, output_root: str | os.PathLike, sphinx_build_path: str, extra_package_path: str, executable=sys.executable):
14
14
  py2docfx_logger = get_package_logger(__name__, pkg.name)
15
15
  # Copy manual written RST from target doc repo
16
16
  package_paths = pkg.path
@@ -45,7 +45,7 @@ def generate_document(pkg: PackageInfo, output_root: str | os.PathLike, sphinx_b
45
45
  py2docfx_logger.info(msg)
46
46
 
47
47
  generate_conf(pkg, package_paths.doc_folder, CONF_TEMPLATE_DIR)
48
- run_converter(pkg.name, package_paths.doc_folder, package_paths.yaml_output_folder, sphinx_build_path, extra_package_path, executable=executable)
48
+ await run_converter(pkg.name, package_paths.doc_folder, package_paths.yaml_output_folder, sphinx_build_path, extra_package_path, executable=executable)
49
49
 
50
50
  subpackages_path_record = {}
51
51
  if pkg.build_in_subpackage:
@@ -53,6 +53,6 @@ def generate_document(pkg: PackageInfo, output_root: str | os.PathLike, sphinx_b
53
53
  for (subpackage_name, subpackage_path) in subpackages_rst_record.items():
54
54
  subpackage_yaml_path = os.path.join(subpackages_yaml_path, subpackage_name)
55
55
  subpackages_path_record[subpackage_name] = subpackage_yaml_path
56
- run_converter(pkg.name, subpackage_path, subpackage_yaml_path, sphinx_build_path, extra_package_path, executable=executable)
56
+ await run_converter(pkg.name, subpackage_path, subpackage_yaml_path, sphinx_build_path, extra_package_path, executable=executable)
57
57
 
58
58
  merge_subpackage_files(subpackages_path_record, package_paths.yaml_output_folder, pkg.name)
@@ -124,6 +124,6 @@ def get_source(executable: str, pkg: PackageInfo, cnt: int, vststoken=None, gith
124
124
  else:
125
125
  msg = f"Unknown install type: {pkg.install_type}"
126
126
  py2docfx_logger.error(msg)
127
- raise ValueError()
127
+ raise ValueError(msg)
128
128
 
129
129
  update_package_info(executable, pkg, source_folder)
@@ -22,7 +22,7 @@ def clone(repo_location, branch, folder, extra_token=None):
22
22
  if not test_url(repo_location, extra_token):
23
23
  msg = "Git repo address {} is not a valid URL.".format(repo_location)
24
24
  py2docfx_logger.error(msg)
25
- raise ValueError()
25
+ raise ValueError(msg)
26
26
  else:
27
27
  # Remove http(s):// from url to record. Further avoid dup-clone.
28
28
  pureURL = re.sub("^\s*https?://", "", repo_location)
@@ -26,7 +26,7 @@ class PackageInfo:
26
26
  name, value
27
27
  )
28
28
  py2docfx_logger.error(message)
29
- raise ValueError()
29
+ raise ValueError(message)
30
30
 
31
31
  @classmethod
32
32
  def parse_from(cls, dict, reading_required_packages=False):
@@ -64,7 +64,7 @@ class PackageInfo:
64
64
  if not package_info.folder:
65
65
  msg = "When install_type is source_code, url or folder should be provided"
66
66
  py2docfx_logger.error(msg)
67
- raise ValueError()
67
+ raise ValueError(msg)
68
68
  else:
69
69
  msg = f'Read source code from local folder: {package_info.folder}'
70
70
  py2docfx_logger.info(msg)
@@ -149,7 +149,7 @@ class PackageInfo:
149
149
  else:
150
150
  msg = "Should set source code location before build documents"
151
151
  py2docfx_logger.error(msg)
152
- raise ValueError()
152
+ raise ValueError(msg)
153
153
  exclude_path = []
154
154
  if code_location:
155
155
  exclude_path.append(os.path.join(code_location, "build/*"))
@@ -21,8 +21,9 @@ def merge_toc(
21
21
  if not toc_content.endswith("\n"):
22
22
  root_toc_handle.write("\n")
23
23
  else:
24
- py2docfx_logger.error(f"TOC content empty: {package_toc_path}")
25
- raise ValueError()
24
+ msg = f"TOC content empty: {package_toc_path}"
25
+ py2docfx_logger.error(msg)
26
+ raise ValueError(msg)
26
27
 
27
28
  # delete package toc.yml
28
29
  os.remove(package_toc_path)
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import os
2
3
  import subprocess
3
4
  import sys
@@ -49,7 +50,7 @@ def run_apidoc(package_name, rst_path, source_code_path, exclude_paths, package_
49
50
  return subpackages_rst_record
50
51
 
51
52
 
52
- def run_converter(package_name: str,
53
+ async def run_converter(package_name: str,
53
54
  rst_path,
54
55
  out_path,
55
56
  sphinx_build_path: str,
@@ -73,9 +74,8 @@ def run_converter(package_name: str,
73
74
  if not sys.executable:
74
75
  msg = "Can't get the executable binary for the Python interpreter."
75
76
  py2docfx_logger.error(msg)
76
- raise ValueError()
77
+ raise ValueError(msg)
77
78
  sphinx_param = [
78
- executable,
79
79
  sphinx_build_path,
80
80
  rst_path,
81
81
  outdir,
@@ -92,8 +92,22 @@ def run_converter(package_name: str,
92
92
  env_tmp["PYTHONPATH"] = f"{extra_package_path};{package_root_parent};"
93
93
  else:
94
94
  env_tmp["PYTHONPATH"] = f"{extra_package_path}:{package_root_parent}:"
95
-
96
- output = subprocess.run(sphinx_param, check=False, cwd=PACKAGE_ROOT, env=env_tmp, capture_output=True ,text=True)
97
- log_subprocess_ouput(output, py2docfx_logger)
95
+ os.environ['PROCESSING_PACKAGE_NAME'] = package_name
96
+ proc = await asyncio.create_subprocess_exec(
97
+ executable, *sphinx_param,
98
+ cwd=PACKAGE_ROOT,
99
+ env=env_tmp,
100
+ stdout=asyncio.subprocess.PIPE,
101
+ stderr=asyncio.subprocess.PIPE
102
+ )
103
+ stdout, stderr = await proc.communicate()
104
+ return_code = proc.returncode
105
+
106
+ if return_code == 0:
107
+ py2docfx_logger.info(f"{stdout}")
108
+ py2docfx_logger.info(f"{stderr}")
109
+ else:
110
+ py2docfx_logger.error(f"{stderr}")
111
+ raise subprocess.CalledProcessError(return_code, sphinx_param, stdout, stderr)
98
112
 
99
113
  return outdir
@@ -12,7 +12,6 @@ from py2docfx.convert_prepare.environment import prepare_base_venv
12
12
  from py2docfx.convert_prepare.environment import get_base_venv_exe
13
13
  from py2docfx.convert_prepare.environment import get_base_venv_path
14
14
  from py2docfx.convert_prepare.package_info import PackageInfo
15
- pytest_plugins = ('pytest_asyncio',)
16
15
 
17
16
  @pytest.mark.asyncio
18
17
  async def test_venv_creation_package_install_remove():
@@ -4,6 +4,7 @@ Test the generate_document function.
4
4
  import os
5
5
  import sys
6
6
  import shutil
7
+ import pytest
7
8
  import sphinx
8
9
  import sphinx.cmd.build
9
10
 
@@ -11,7 +12,8 @@ from py2docfx.convert_prepare.generate_document import generate_document
11
12
  from py2docfx.convert_prepare.package_info import PackageInfo
12
13
  from py2docfx.convert_prepare.source import Source
13
14
 
14
- def test_generate_document(tmp_path):
15
+ @pytest.mark.asyncio
16
+ async def test_generate_document(tmp_path):
15
17
  """
16
18
  Test the generate_document function.
17
19
  """
@@ -42,7 +44,7 @@ def test_generate_document(tmp_path):
42
44
 
43
45
  # call the function
44
46
 
45
- generate_document(package, output_root, sphinx_build_path = sphinx.cmd.build.__file__, extra_package_path = source_folder)
47
+ await generate_document(package, output_root, sphinx_build_path = sphinx.cmd.build.__file__, extra_package_path = source_folder)
46
48
 
47
49
  #assert the result
48
50
  yaml_path = os.path.join(yaml_output_folder, "_build", "docfx_yaml")
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import shutil
3
+ import pytest
3
4
  import sphinx
4
5
  import sphinx.cmd.build
5
6
 
@@ -34,8 +35,8 @@ def test_run_apidoc(tmp_path):
34
35
  assert "testcode.fakemodule.rst" in rst_list
35
36
  assert "testcode.exclude.rst" not in rst_list
36
37
 
37
-
38
- def test_run_converter(tmp_path):
38
+ @pytest.mark.asyncio
39
+ async def test_run_converter(tmp_path):
39
40
  rst_path, source_code_path = init_paths(tmp_path)
40
41
  package_name = "testcode"
41
42
  run_apidoc(package_name, rst_path, source_code_path, package_info.get_exluded_command(), package_info)
@@ -50,7 +51,7 @@ def test_run_converter(tmp_path):
50
51
  index_rst.write("")
51
52
 
52
53
  out_path = os.path.join(tmp_path, "out")
53
- out_path = run_converter(package_name, rst_path, out_path, sphinx_build_path = sphinx.cmd.build.__file__, extra_package_path = source_code_path, conf_path=rst_path)
54
+ out_path = await run_converter(package_name, rst_path, out_path, sphinx_build_path = sphinx.cmd.build.__file__, extra_package_path = source_code_path, conf_path=rst_path)
54
55
 
55
56
  if os.path.exists(out_path):
56
57
  yaml_list = os.listdir(os.path.join(out_path, "docfx_yaml"))
@@ -34,7 +34,10 @@ def check_log_file_exists(log_file_path):
34
34
  with open(log_file_path, 'w') as f:
35
35
  f.write('')
36
36
 
37
- def setup_log_handlers(logger, log_file_name):
37
+ def setup_log_handlers(logger_name, log_file_name, log_folder_path):
38
+ check_log_dir_exists(log_folder_path)
39
+ logger = logging.getLogger(logger_name)
40
+ logger.setLevel(logging.INFO)
38
41
  check_log_file_exists(log_file_name)
39
42
  if logger.hasHandlers():
40
43
  logger.handlers.clear()
@@ -47,12 +50,8 @@ def setup_log_handlers(logger, log_file_name):
47
50
  def get_logger(logger_name: str):
48
51
  log_folder_path = os.path.join("logs")
49
52
  file_name = os.path.join(log_folder_path, "log.txt")
50
-
51
- file_logger = logging.getLogger(logger_name)
52
- file_logger.setLevel(logging.INFO)
53
- check_log_dir_exists(log_folder_path)
54
-
55
- file_logger = setup_log_handlers(file_logger, file_name)
53
+
54
+ file_logger = setup_log_handlers(logger_name, file_name, log_folder_path)
56
55
 
57
56
  return file_logger
58
57
 
@@ -61,13 +60,9 @@ def get_package_logger(logger_name:str, package_name:str = None):
61
60
  if package_name is None:
62
61
  package_name = os.environ.get('PROCESSING_PACKAGE_NAME')
63
62
  file_name = os.path.join(log_folder_path, f"{package_name}.txt")
64
-
65
- file_logger = logging.getLogger(logger_name)
66
- file_logger.setLevel(logging.INFO)
67
- check_log_dir_exists(log_folder_path)
68
63
 
69
- file_logger = setup_log_handlers(file_logger, file_name)
70
-
64
+ file_logger = setup_log_handlers(logger_name, file_name, log_folder_path)
65
+
71
66
  return file_logger
72
67
 
73
68
  def log_subprocess_ouput(subprocess_out: subprocess.CompletedProcess, logger: logging.Logger):
@@ -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