py2docfx 0.1.20rc2196756__py3-none-any.whl → 0.1.21.dev2246704__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 (140) hide show
  1. py2docfx/convert_prepare/get_source.py +1 -1
  2. py2docfx/convert_prepare/package_info.py +37 -27
  3. py2docfx/convert_prepare/tests/test_get_source.py +3 -1
  4. py2docfx/convert_prepare/tests/test_package_info.py +159 -1
  5. py2docfx/docfx_yaml/build_finished.py +1 -1
  6. py2docfx/docfx_yaml/logger.py +42 -28
  7. py2docfx/venv/basevenv/Lib/site-packages/charset_normalizer/api.py +3 -2
  8. py2docfx/venv/basevenv/Lib/site-packages/charset_normalizer/legacy.py +17 -1
  9. py2docfx/venv/basevenv/Lib/site-packages/charset_normalizer/version.py +1 -1
  10. py2docfx/venv/basevenv/Lib/site-packages/requests/__version__.py +2 -2
  11. py2docfx/venv/basevenv/Lib/site-packages/requests/adapters.py +17 -40
  12. py2docfx/venv/basevenv/Lib/site-packages/requests/sessions.py +1 -1
  13. py2docfx/venv/venv1/Lib/site-packages/azure/core/_version.py +1 -1
  14. py2docfx/venv/venv1/Lib/site-packages/azure/core/pipeline/policies/_authentication.py +21 -9
  15. py2docfx/venv/venv1/Lib/site-packages/azure/core/pipeline/policies/_authentication_async.py +21 -9
  16. py2docfx/venv/venv1/Lib/site-packages/azure/core/pipeline/policies/_retry.py +1 -1
  17. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_bearer_token_provider.py +1 -1
  18. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/authorization_code.py +1 -1
  19. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azd_cli.py +82 -17
  20. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_cli.py +28 -5
  21. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_powershell.py +28 -4
  22. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/broker.py +79 -0
  23. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/chained.py +9 -3
  24. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +153 -53
  25. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +25 -1
  26. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/shared_cache.py +12 -5
  27. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/vscode.py +163 -144
  28. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/workload_identity.py +23 -12
  29. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/__init__.py +4 -0
  30. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +14 -2
  31. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/pipeline.py +4 -2
  32. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/utils.py +96 -0
  33. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
  34. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_bearer_token_provider.py +3 -3
  35. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/authorization_code.py +1 -1
  36. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azd_cli.py +32 -13
  37. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_cli.py +26 -5
  38. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_powershell.py +13 -2
  39. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/chained.py +1 -1
  40. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +120 -55
  41. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +27 -1
  42. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/on_behalf_of.py +1 -1
  43. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/shared_cache.py +12 -5
  44. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/vscode.py +15 -67
  45. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/workload_identity.py +17 -13
  46. py2docfx/venv/venv1/Lib/site-packages/cffi/__init__.py +2 -2
  47. py2docfx/venv/venv1/Lib/site-packages/cffi/cparser.py +1 -1
  48. py2docfx/venv/venv1/Lib/site-packages/cffi/recompiler.py +5 -5
  49. py2docfx/venv/venv1/Lib/site-packages/cffi/setuptools_ext.py +13 -0
  50. py2docfx/venv/venv1/Lib/site-packages/cffi/vengine_cpy.py +3 -0
  51. py2docfx/venv/venv1/Lib/site-packages/charset_normalizer/api.py +3 -2
  52. py2docfx/venv/venv1/Lib/site-packages/charset_normalizer/legacy.py +17 -1
  53. py2docfx/venv/venv1/Lib/site-packages/charset_normalizer/version.py +1 -1
  54. py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
  55. py2docfx/venv/venv1/Lib/site-packages/cryptography/__init__.py +0 -13
  56. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/_oid.py +8 -0
  57. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/asn1/__init__.py +10 -0
  58. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/asn1/asn1.py +116 -0
  59. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py +3 -9
  60. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi +32 -0
  61. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi +23 -0
  62. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi +1 -13
  63. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py +16 -0
  64. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py +16 -1
  65. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py +0 -2
  66. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py +8 -0
  67. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py +0 -47
  68. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +6 -91
  69. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +1 -3
  70. py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +1 -1
  71. py2docfx/venv/venv1/Lib/site-packages/cryptography/utils.py +0 -2
  72. py2docfx/venv/venv1/Lib/site-packages/cryptography/x509/name.py +2 -3
  73. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/__init__.py +1 -1
  74. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/any_pb2.py +2 -2
  75. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/api_pb2.py +12 -8
  76. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/compiler/plugin_pb2.py +2 -2
  77. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/descriptor.py +398 -246
  78. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/descriptor_pb2.py +74 -72
  79. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/descriptor_pool.py +5 -4
  80. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/duration_pb2.py +2 -2
  81. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/empty_pb2.py +2 -2
  82. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/field_mask_pb2.py +2 -2
  83. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/api_implementation.py +0 -6
  84. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/extension_dict.py +3 -3
  85. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/field_mask.py +3 -3
  86. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/python_edition_defaults.py +1 -1
  87. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/python_message.py +10 -2
  88. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/type_checkers.py +47 -5
  89. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/json_format.py +55 -32
  90. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/runtime_version.py +6 -26
  91. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/source_context_pb2.py +2 -2
  92. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/struct_pb2.py +2 -2
  93. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/text_format.py +30 -19
  94. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/timestamp_pb2.py +2 -2
  95. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/type_pb2.py +2 -2
  96. py2docfx/venv/venv1/Lib/site-packages/google/protobuf/wrappers_pb2.py +2 -2
  97. py2docfx/venv/venv1/Lib/site-packages/psutil/__init__.py +39 -19
  98. py2docfx/venv/venv1/Lib/site-packages/psutil/_common.py +3 -5
  99. py2docfx/venv/venv1/Lib/site-packages/psutil/_psaix.py +1 -2
  100. py2docfx/venv/venv1/Lib/site-packages/psutil/_psbsd.py +53 -78
  101. py2docfx/venv/venv1/Lib/site-packages/psutil/_pslinux.py +55 -38
  102. py2docfx/venv/venv1/Lib/site-packages/psutil/_psosx.py +40 -12
  103. py2docfx/venv/venv1/Lib/site-packages/psutil/_psposix.py +0 -1
  104. py2docfx/venv/venv1/Lib/site-packages/psutil/_pssunos.py +1 -2
  105. py2docfx/venv/venv1/Lib/site-packages/psutil/_pswindows.py +33 -13
  106. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__init__.py +185 -122
  107. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__main__.py +2 -3
  108. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_bsd.py +5 -10
  109. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_connections.py +3 -4
  110. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_contracts.py +41 -45
  111. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_linux.py +35 -38
  112. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_memleaks.py +4 -8
  113. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_misc.py +6 -12
  114. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_osx.py +17 -8
  115. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_posix.py +29 -17
  116. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process.py +74 -75
  117. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process_all.py +11 -13
  118. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_scripts.py +2 -3
  119. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_sudo.py +117 -0
  120. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_system.py +21 -31
  121. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_testutils.py +23 -23
  122. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_unicode.py +15 -8
  123. py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_windows.py +65 -33
  124. py2docfx/venv/venv1/Lib/site-packages/pycparser/__init__.py +1 -1
  125. py2docfx/venv/venv1/Lib/site-packages/pycparser/c_generator.py +1 -1
  126. py2docfx/venv/venv1/Lib/site-packages/pycparser/c_lexer.py +14 -0
  127. py2docfx/venv/venv1/Lib/site-packages/pycparser/c_parser.py +30 -7
  128. py2docfx/venv/venv1/Lib/site-packages/pycparser/lextab.py +1 -1
  129. py2docfx/venv/venv1/Lib/site-packages/pycparser/yacctab.py +132 -127
  130. py2docfx/venv/venv1/Lib/site-packages/requests/__version__.py +2 -2
  131. py2docfx/venv/venv1/Lib/site-packages/requests/adapters.py +17 -40
  132. py2docfx/venv/venv1/Lib/site-packages/requests/sessions.py +1 -1
  133. py2docfx/venv/venv1/Lib/site-packages/typing_extensions.py +91 -18
  134. {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/METADATA +1 -1
  135. {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/RECORD +137 -135
  136. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/linux_vscode_adapter.py +0 -100
  137. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/macos_vscode_adapter.py +0 -34
  138. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/win_vscode_adapter.py +0 -77
  139. {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/WHEEL +0 -0
  140. {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/top_level.txt +0 -0
@@ -54,7 +54,7 @@ def update_package_info(executable: str, pkg: PackageInfo, source_folder: str):
54
54
  for meta_info in metadata:
55
55
  meta_info_array = meta_info.split(":")
56
56
  meta_field = meta_info_array[0].strip().lower()
57
- if meta_field in attrs:
57
+ if meta_field in attrs and not hasattr(pkg, meta_field):
58
58
  setattr(
59
59
  pkg,
60
60
  meta_field,
@@ -13,7 +13,7 @@ class PackageInfo:
13
13
  path: Source
14
14
  def __init__(self) -> None:
15
15
  pass
16
-
16
+
17
17
  @classmethod
18
18
  def report_error(cls, name, value, condition=None):
19
19
  py2docfx_logger = get_logger(__name__)
@@ -53,6 +53,7 @@ class PackageInfo:
53
53
 
54
54
  package_info.version = package_info_dict.get("version", None)
55
55
  package_info.extra_index_url = package_info_dict.get("extra_index_url", None)
56
+ package_info.extras = package_info_dict.get("extras", [])
56
57
 
57
58
  if package_info.install_type == cls.InstallType.SOURCE_CODE:
58
59
  package_info.url = package_info_dict.get("url", None)
@@ -93,56 +94,65 @@ class PackageInfo:
93
94
  return package_info
94
95
 
95
96
  def get_combined_name_version(self):
96
- if not self.version:
97
- return self.name
98
- elif re.match("^(<|>|<=|>=|==).+$", self.version.strip()):
99
- return self.name.strip() + self.version.strip()
100
- else:
101
- return f"{self.name.strip()}=={self.version.strip()}"
97
+ base_name = (
98
+ f"{self.name}[{','.join(extras)}]"
99
+ if (extras := getattr(self, "extras", []))
100
+ else self.name
101
+ )
102
102
 
103
- def get_install_command(self) -> (str, []):
104
- packageInstallName = ""
105
- pipInstallExtraOptions = []
103
+ version = getattr(self, "version", None)
104
+ if not version:
105
+ return base_name
106
+ elif re.match("^(<|>|<=|>=|==).+$", version.strip()):
107
+ return base_name.strip() + version.strip()
108
+ else:
109
+ return f"{base_name.strip()}=={version.strip()}"
106
110
 
111
+ def get_install_command(self) -> tuple[str, list]:
107
112
  if self.install_type == self.InstallType.DIST_FILE:
108
- if hasattr(self, "location") and self.location:
109
- packageInstallName = self.location
110
- else:
113
+ if not hasattr(self, "location") or not self.location:
111
114
  self.__class__.report_error(
112
115
  "location", "None", condition="When install_type is dist_file"
113
116
  )
117
+ return (
118
+ f"{self.location}[{','.join(extras)}]"
119
+ if (extras := getattr(self, "extras", None))
120
+ else self.location,
121
+ [],
122
+ )
114
123
 
115
- elif self.install_type == self.InstallType.PYPI:
124
+ if self.install_type == self.InstallType.PYPI:
116
125
  if not hasattr(self, "name") or not self.name:
117
126
  self.__class__.report_error(
118
127
  "name", "None", condition="When install_type is pypi"
119
128
  )
120
- if hasattr(self, "version") and self.version:
121
- packageInstallName = self.get_combined_name_version()
122
- else:
123
- packageInstallName = self.name
129
+ pipInstallExtraOptions = []
130
+ if not hasattr(self, "version") or self.version is None:
124
131
  pipInstallExtraOptions.append("--upgrade")
125
-
126
132
  if hasattr(self, "extra_index_url") and self.extra_index_url:
127
133
  pipInstallExtraOptions.extend(
128
134
  ["--extra-index-url", self.extra_index_url]
129
135
  )
136
+ return (self.get_combined_name_version(), pipInstallExtraOptions)
130
137
 
131
- elif self.install_type == self.InstallType.SOURCE_CODE:
132
- if hasattr(self, "path") and self.path.source_folder:
133
- packageInstallName = self.path.source_folder
134
- else:
138
+ if self.install_type == self.InstallType.SOURCE_CODE:
139
+ if not hasattr(self, "path") or not self.path.source_folder:
135
140
  self.__class__.report_error(
136
141
  "path.source_folder",
137
142
  "None",
138
143
  condition="When install_type is source_code",
139
144
  )
140
- else:
141
- self.__class__.report_error("install_type", self.install_type)
145
+ return (
146
+ f"{self.path.source_folder}[{','.join(extras)}]"
147
+ if (extras := getattr(self, "extras", None))
148
+ else self.path.source_folder,
149
+ [],
150
+ )
151
+
152
+ self.__class__.report_error("install_type", self.install_type)
142
153
 
143
- return (packageInstallName, pipInstallExtraOptions)
144
154
 
145
- def get_exluded_command(self) -> []:
155
+ def get_exluded_command(self) -> list:
146
156
  py2docfx_logger = get_logger(__name__)
147
157
  if hasattr(self, "path"):
148
158
  code_location = self.path.source_folder
@@ -50,8 +50,10 @@ def test_update_package_info(init_package_info):
50
50
  assert package.name == "dummy_package"
51
51
  assert package.version == "3.1.0"
52
52
 
53
- # case of metadata
53
+ # case of metadata, unly use metadata file as a fallback
54
54
  package = init_package_info
55
+ del package.name
56
+ del package.version
55
57
  get_source.update_package_info(sys.executable, package, os.path.join(base_path, "mock-2"))
56
58
  assert package.name == "mock_package"
57
59
  assert package.version == "2.2.0"
@@ -80,4 +80,162 @@ def test_get_exclude_command_check_extra_exclude(tmp_path):
80
80
  ]
81
81
  def form_exclude_path(raletive_path):
82
82
  return os.path.join(source_folder, raletive_path)
83
- assert exclude_path == [form_exclude_path(path) for path in expected_exclude_path]
83
+ assert exclude_path == [form_exclude_path(path) for path in expected_exclude_path]
84
+
85
+
86
+ def test_get_combined_name_version_with_extras():
87
+ """Test get_combined_name_version with extras"""
88
+ # Test package with extras but no version
89
+ test_data = {
90
+ "package_info": {
91
+ "install_type": "pypi",
92
+ "name": "test-package",
93
+ "extras": ["dev", "test"],
94
+ },
95
+ }
96
+ pkg = PackageInfo.parse_from(test_data)
97
+ assert pkg.get_combined_name_version() == "test-package[dev,test]"
98
+
99
+ # Test package with extras and version
100
+ test_data_with_version = {
101
+ "package_info": {
102
+ "install_type": "pypi",
103
+ "name": "test-package",
104
+ "version": "1.0.0",
105
+ "extras": ["dev", "test"],
106
+ },
107
+ }
108
+ pkg_with_version = PackageInfo.parse_from(test_data_with_version)
109
+ assert (
110
+ pkg_with_version.get_combined_name_version() == "test-package[dev,test]==1.0.0"
111
+ )
112
+
113
+ # Test package with extras and version operator
114
+ test_data_with_operator = {
115
+ "package_info": {
116
+ "install_type": "pypi",
117
+ "name": "test-package",
118
+ "version": ">=1.0.0",
119
+ "extras": ["dev"],
120
+ },
121
+ }
122
+ pkg_with_operator = PackageInfo.parse_from(test_data_with_operator)
123
+ assert pkg_with_operator.get_combined_name_version() == "test-package[dev]>=1.0.0"
124
+
125
+
126
+ def test_install_command_pypi_with_extras():
127
+ """Test get_install_command for PYPI packages with extras"""
128
+ # Test PYPI package with extras and version
129
+ test_data = {
130
+ "package_info": {
131
+ "install_type": "pypi",
132
+ "name": "test-package",
133
+ "version": "1.0.0",
134
+ "extras": ["dev", "test"],
135
+ },
136
+ }
137
+ pkg = PackageInfo.parse_from(test_data)
138
+ install_command = pkg.get_install_command()
139
+ assert install_command[0] == "test-package[dev,test]==1.0.0"
140
+ assert install_command[1] == []
141
+
142
+ # Test PYPI package with extras but no version (should get --upgrade)
143
+ test_data_no_version = {
144
+ "package_info": {
145
+ "install_type": "pypi",
146
+ "name": "test-package",
147
+ "extras": ["dev"],
148
+ },
149
+ }
150
+ pkg_no_version = PackageInfo.parse_from(test_data_no_version)
151
+ install_command = pkg_no_version.get_install_command()
152
+ assert install_command[0] == "test-package[dev]"
153
+ assert install_command[1] == ["--upgrade"]
154
+
155
+
156
+ def test_install_command_source_code_with_extras(tmp_path):
157
+ """Test get_install_command for SOURCE_CODE packages with extras"""
158
+ source_folder = os.path.join(tmp_path, "source_folder")
159
+ yaml_output_folder = os.path.join(tmp_path, "yaml_output_folder")
160
+
161
+ test_data = {
162
+ "package_info": {
163
+ "install_type": "source_code",
164
+ "name": "test-package",
165
+ "url": "https://github.com/test/test-package.git",
166
+ "extras": ["dev", "test"],
167
+ },
168
+ }
169
+ pkg = PackageInfo.parse_from(test_data)
170
+ pkg.path = Source(
171
+ source_folder=source_folder,
172
+ yaml_output_folder=yaml_output_folder,
173
+ package_name="test-package",
174
+ )
175
+
176
+ install_command = pkg.get_install_command()
177
+ assert install_command[0] == f"{source_folder}[dev,test]"
178
+ assert install_command[1] == []
179
+
180
+
181
+ def test_install_command_dist_file_with_extras():
182
+ """Test get_install_command for DIST_FILE packages with extras"""
183
+ test_data = {
184
+ "package_info": {
185
+ "install_type": "dist_file",
186
+ "location": "/path/to/package.whl",
187
+ "extras": ["dev"],
188
+ },
189
+ }
190
+ pkg = PackageInfo.parse_from(test_data)
191
+ install_command = pkg.get_install_command()
192
+ assert install_command[0] == "/path/to/package.whl[dev]"
193
+ assert install_command[1] == []
194
+
195
+
196
+ def test_install_command_without_extras():
197
+ """Test that packages without extras work as before"""
198
+ # Test PYPI package without extras
199
+ test_data = {
200
+ "package_info": {
201
+ "install_type": "pypi",
202
+ "name": "test-package",
203
+ "version": "1.0.0",
204
+ }
205
+ }
206
+ pkg = PackageInfo.parse_from(test_data)
207
+ install_command = pkg.get_install_command()
208
+ assert install_command[0] == "test-package==1.0.0"
209
+ assert install_command[1] == []
210
+
211
+
212
+ def test_install_command_empty_extras():
213
+ """Test that packages with empty extras list work correctly"""
214
+ test_data = {
215
+ "package_info": {
216
+ "install_type": "pypi",
217
+ "name": "test-package",
218
+ "version": "1.0.0",
219
+ "extras": [],
220
+ },
221
+ }
222
+ pkg = PackageInfo.parse_from(test_data)
223
+ install_command = pkg.get_install_command()
224
+ assert install_command[0] == "test-package==1.0.0"
225
+ assert install_command[1] == []
226
+
227
+
228
+ def test_install_command_single_extra():
229
+ """Test package with single extra"""
230
+ test_data = {
231
+ "package_info": {
232
+ "install_type": "pypi",
233
+ "name": "test-package",
234
+ "version": "1.0.0",
235
+ "extras": ["dev"],
236
+ },
237
+ }
238
+ pkg = PackageInfo.parse_from(test_data)
239
+ install_command = pkg.get_install_command()
240
+ assert install_command[0] == "test-package[dev]==1.0.0"
241
+ assert install_command[1] == []
@@ -277,7 +277,7 @@ def build_finished(app, exception):
277
277
  obj['kind'] = 'import'
278
278
  package_obj = obj
279
279
 
280
- if (obj['type'] == 'class' and obj['inheritance']):
280
+ if (obj['type'] == 'class' and 'inheritance' in obj):
281
281
  convert_class_to_enum_if_needed(obj)
282
282
 
283
283
  is_root = insert_node_to_toc_tree_return_is_root_package(toc_yaml, uid, project_name, toc_node_map)
@@ -77,18 +77,18 @@ def counts_errors_warnings(log_file_path):
77
77
  warning_count += 1
78
78
  return warning_count, error_count
79
79
 
80
- def get_warning_error_count():
81
- main_log_file_path = os.path.join("logs", "log.txt")
82
- warning_count, error_count = counts_errors_warnings(main_log_file_path)
83
-
84
- log_folder_path = os.path.join("logs", "package_logs")
85
- # Check if the directory exists before trying to list its contents
86
- if os.path.exists(log_folder_path) and os.path.isdir(log_folder_path):
87
- for log_file in os.listdir(log_folder_path):
88
- log_file_path = os.path.join(log_folder_path, log_file)
89
- warnings, errors = counts_errors_warnings(log_file_path)
90
- warning_count += warnings
91
- error_count += errors
80
+ def get_warning_error_count():
81
+ main_log_file_path = os.path.join("logs", "log.txt")
82
+ warning_count, error_count = counts_errors_warnings(main_log_file_path)
83
+
84
+ log_folder_path = os.path.join("logs", "package_logs")
85
+ # Check if the directory exists before trying to list its contents
86
+ if os.path.exists(log_folder_path) and os.path.isdir(log_folder_path):
87
+ for log_file in os.listdir(log_folder_path):
88
+ log_file_path = os.path.join(log_folder_path, log_file)
89
+ warnings, errors = counts_errors_warnings(log_file_path)
90
+ warning_count += warnings
91
+ error_count += errors
92
92
 
93
93
  return warning_count, error_count
94
94
 
@@ -120,16 +120,16 @@ def print_out_log_by_log_level(log_list, log_level):
120
120
  if log['level'] >= log_level and log['message'] not in ['', '\n', '\r\n']:
121
121
  print(log['message'])
122
122
 
123
- def output_log_by_log_level():
124
- log_level = get_log_level()
125
- main_log_file_path = os.path.join("logs", "log.txt")
126
- print_out_log_by_log_level(parse_log(main_log_file_path), log_level)
127
-
128
- package_logs_folder = os.path.join("logs", "package_logs")
129
- # Check if the directory exists before trying to list its contents
130
- if os.path.exists(package_logs_folder) and os.path.isdir(package_logs_folder):
131
- for log_file in os.listdir(package_logs_folder):
132
- log_file_path = os.path.join(package_logs_folder, log_file)
123
+ def output_log_by_log_level():
124
+ log_level = get_log_level()
125
+ main_log_file_path = os.path.join("logs", "log.txt")
126
+ print_out_log_by_log_level(parse_log(main_log_file_path), log_level)
127
+
128
+ package_logs_folder = os.path.join("logs", "package_logs")
129
+ # Check if the directory exists before trying to list its contents
130
+ if os.path.exists(package_logs_folder) and os.path.isdir(package_logs_folder):
131
+ for log_file in os.listdir(package_logs_folder):
132
+ log_file_path = os.path.join(package_logs_folder, log_file)
133
133
  print_out_log_by_log_level(parse_log(log_file_path), log_level)
134
134
 
135
135
  async def run_async_subprocess(exe_path, cmd, logger, cwd=None):
@@ -148,9 +148,16 @@ async def run_async_subprocess(exe_path, cmd, logger, cwd=None):
148
148
  )
149
149
  stdout, stderr = await process.communicate()
150
150
  if process.returncode != 0:
151
- msg = stderr.decode('utf-8')
152
- if msg != None and msg != "":
153
- logger.error(msg)
151
+ # Log both stdout and stderr on failure - pip often outputs detailed
152
+ # dependency resolution errors to stdout even when it fails
153
+ stdout_msg = stdout.decode('utf-8')
154
+ stderr_msg = stderr.decode('utf-8')
155
+
156
+ if stdout_msg and stdout_msg.strip():
157
+ logger.error(f"STDOUT: {stdout_msg}")
158
+ if stderr_msg and stderr_msg.strip():
159
+ logger.error(f"STDERR: {stderr_msg}")
160
+
154
161
  raise subprocess.CalledProcessError(process.returncode, cmd, stdout, stderr)
155
162
  else:
156
163
  msg = stdout.decode('utf-8')
@@ -174,9 +181,16 @@ async def run_async_subprocess_without_executable(cmd, logger, cwd=None):
174
181
 
175
182
  stdout, stderr = await process.communicate()
176
183
  if process.returncode != 0:
177
- msg = stderr.decode('utf-8')
178
- if msg != None and msg != "":
179
- logger.error(msg)
184
+ # Log both stdout and stderr on failure - pip often outputs detailed
185
+ # dependency resolution errors to stdout even when it fails
186
+ stdout_msg = stdout.decode('utf-8')
187
+ stderr_msg = stderr.decode('utf-8')
188
+
189
+ if stdout_msg and stdout_msg.strip():
190
+ logger.error(f"STDOUT: {stdout_msg}")
191
+ if stderr_msg and stderr_msg.strip():
192
+ logger.error(f"STDERR: {stderr_msg}")
193
+
180
194
  raise subprocess.CalledProcessError(process.returncode, cmd, stdout, stderr)
181
195
  else:
182
196
  msg = stdout.decode('utf-8')
@@ -369,14 +369,15 @@ def from_bytes(
369
369
  # Preparing those fallbacks in case we got nothing.
370
370
  if (
371
371
  enable_fallback
372
- and encoding_iana in ["ascii", "utf_8", specified_encoding]
372
+ and encoding_iana
373
+ in ["ascii", "utf_8", specified_encoding, "utf_16", "utf_32"]
373
374
  and not lazy_str_hard_failure
374
375
  ):
375
376
  fallback_entry = CharsetMatch(
376
377
  sequences,
377
378
  encoding_iana,
378
379
  threshold,
379
- False,
380
+ bom_or_sig_available,
380
381
  [],
381
382
  decoded_payload,
382
383
  preemptive_declaration=specified_encoding,
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any
4
4
  from warnings import warn
5
5
 
6
6
  from .api import from_bytes
7
- from .constant import CHARDET_CORRESPONDENCE
7
+ from .constant import CHARDET_CORRESPONDENCE, TOO_SMALL_SEQUENCE
8
8
 
9
9
  # TODO: remove this check when dropping Python 3.7 support
10
10
  if TYPE_CHECKING:
@@ -49,6 +49,22 @@ def detect(
49
49
  language = r.language if r is not None and r.language != "Unknown" else ""
50
50
  confidence = 1.0 - r.chaos if r is not None else None
51
51
 
52
+ # automatically lower confidence
53
+ # on small bytes samples.
54
+ # https://github.com/jawah/charset_normalizer/issues/391
55
+ if (
56
+ confidence is not None
57
+ and confidence >= 0.9
58
+ and encoding
59
+ not in {
60
+ "utf_8",
61
+ "ascii",
62
+ }
63
+ and r.bom is False # type: ignore[union-attr]
64
+ and len(byte_str) < TOO_SMALL_SEQUENCE
65
+ ):
66
+ confidence -= 0.2
67
+
52
68
  # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process
53
69
  # but chardet does return 'utf-8-sig' and it is a valid codec name.
54
70
  if r is not None and encoding == "utf_8" and r.bom:
@@ -4,5 +4,5 @@ Expose version
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- __version__ = "3.4.2"
7
+ __version__ = "3.4.3"
8
8
  VERSION = __version__.split(".")
@@ -5,8 +5,8 @@
5
5
  __title__ = "requests"
6
6
  __description__ = "Python HTTP for Humans."
7
7
  __url__ = "https://requests.readthedocs.io"
8
- __version__ = "2.32.4"
9
- __build__ = 0x023204
8
+ __version__ = "2.32.5"
9
+ __build__ = 0x023205
10
10
  __author__ = "Kenneth Reitz"
11
11
  __author_email__ = "me@kennethreitz.org"
12
12
  __license__ = "Apache-2.0"
@@ -27,7 +27,6 @@ from urllib3.poolmanager import PoolManager, proxy_from_url
27
27
  from urllib3.util import Timeout as TimeoutSauce
28
28
  from urllib3.util import parse_url
29
29
  from urllib3.util.retry import Retry
30
- from urllib3.util.ssl_ import create_urllib3_context
31
30
 
32
31
  from .auth import _basic_auth_str
33
32
  from .compat import basestring, urlparse
@@ -74,19 +73,6 @@ DEFAULT_RETRIES = 0
74
73
  DEFAULT_POOL_TIMEOUT = None
75
74
 
76
75
 
77
- try:
78
- import ssl # noqa: F401
79
-
80
- _preloaded_ssl_context = create_urllib3_context()
81
- _preloaded_ssl_context.load_verify_locations(
82
- extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH)
83
- )
84
- except ImportError:
85
- # Bypass default SSLContext creation when Python
86
- # interpreter isn't built with the ssl module.
87
- _preloaded_ssl_context = None
88
-
89
-
90
76
  def _urllib3_request_context(
91
77
  request: "PreparedRequest",
92
78
  verify: "bool | str | None",
@@ -99,19 +85,9 @@ def _urllib3_request_context(
99
85
  scheme = parsed_request_url.scheme.lower()
100
86
  port = parsed_request_url.port
101
87
 
102
- # Determine if we have and should use our default SSLContext
103
- # to optimize performance on standard requests.
104
- poolmanager_kwargs = getattr(poolmanager, "connection_pool_kw", {})
105
- has_poolmanager_ssl_context = poolmanager_kwargs.get("ssl_context")
106
- should_use_default_ssl_context = (
107
- _preloaded_ssl_context is not None and not has_poolmanager_ssl_context
108
- )
109
-
110
88
  cert_reqs = "CERT_REQUIRED"
111
89
  if verify is False:
112
90
  cert_reqs = "CERT_NONE"
113
- elif verify is True and should_use_default_ssl_context:
114
- pool_kwargs["ssl_context"] = _preloaded_ssl_context
115
91
  elif isinstance(verify, str):
116
92
  if not os.path.isdir(verify):
117
93
  pool_kwargs["ca_certs"] = verify
@@ -314,26 +290,27 @@ class HTTPAdapter(BaseAdapter):
314
290
  :param cert: The SSL certificate to verify.
315
291
  """
316
292
  if url.lower().startswith("https") and verify:
317
- conn.cert_reqs = "CERT_REQUIRED"
293
+ cert_loc = None
318
294
 
319
- # Only load the CA certificates if 'verify' is a string indicating the CA bundle to use.
320
- # Otherwise, if verify is a boolean, we don't load anything since
321
- # the connection will be using a context with the default certificates already loaded,
322
- # and this avoids a call to the slow load_verify_locations()
295
+ # Allow self-specified cert location.
323
296
  if verify is not True:
324
- # `verify` must be a str with a path then
325
297
  cert_loc = verify
326
298
 
327
- if not os.path.exists(cert_loc):
328
- raise OSError(
329
- f"Could not find a suitable TLS CA certificate bundle, "
330
- f"invalid path: {cert_loc}"
331
- )
299
+ if not cert_loc:
300
+ cert_loc = extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH)
332
301
 
333
- if not os.path.isdir(cert_loc):
334
- conn.ca_certs = cert_loc
335
- else:
336
- conn.ca_cert_dir = cert_loc
302
+ if not cert_loc or not os.path.exists(cert_loc):
303
+ raise OSError(
304
+ f"Could not find a suitable TLS CA certificate bundle, "
305
+ f"invalid path: {cert_loc}"
306
+ )
307
+
308
+ conn.cert_reqs = "CERT_REQUIRED"
309
+
310
+ if not os.path.isdir(cert_loc):
311
+ conn.ca_certs = cert_loc
312
+ else:
313
+ conn.ca_cert_dir = cert_loc
337
314
  else:
338
315
  conn.cert_reqs = "CERT_NONE"
339
316
  conn.ca_certs = None
@@ -410,7 +387,7 @@ class HTTPAdapter(BaseAdapter):
410
387
  ``"cert_reqs"`` will be set
411
388
  * If ``verify`` is a string, (i.e., it is a user-specified trust bundle)
412
389
  ``"ca_certs"`` will be set if the string is not a directory recognized
413
- by :py:func:`os.path.isdir`, otherwise ``"ca_certs_dir"`` will be
390
+ by :py:func:`os.path.isdir`, otherwise ``"ca_cert_dir"`` will be
414
391
  set.
415
392
  * If ``"cert"`` is specified, ``"cert_file"`` will always be set. If
416
393
  ``"cert"`` is a tuple with a second item, ``"key_file"`` will also
@@ -535,7 +535,7 @@ class Session(SessionRedirectMixin):
535
535
  for multipart encoding upload.
536
536
  :param auth: (optional) Auth tuple or callable to enable
537
537
  Basic/Digest/Custom HTTP Auth.
538
- :param timeout: (optional) How long to wait for the server to send
538
+ :param timeout: (optional) How many seconds to wait for the server to send
539
539
  data before giving up, as a float, or a :ref:`(connect timeout,
540
540
  read timeout) <timeouts>` tuple.
541
541
  :type timeout: float or tuple
@@ -9,4 +9,4 @@
9
9
  # regenerated.
10
10
  # --------------------------------------------------------------------------
11
11
 
12
- VERSION = "1.35.0"
12
+ VERSION = "1.35.1"
@@ -6,12 +6,14 @@
6
6
  import time
7
7
  import base64
8
8
  from typing import TYPE_CHECKING, Optional, TypeVar, MutableMapping, Any, Union, cast
9
+
9
10
  from azure.core.credentials import (
10
11
  TokenCredential,
11
12
  SupportsTokenInfo,
12
13
  TokenRequestOptions,
13
14
  TokenProvider,
14
15
  )
16
+ from azure.core.exceptions import HttpResponseError
15
17
  from azure.core.pipeline import PipelineRequest, PipelineResponse
16
18
  from azure.core.pipeline.transport import (
17
19
  HttpResponse as LegacyHttpResponse,
@@ -165,7 +167,20 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
165
167
  if response.http_response.status_code == 401:
166
168
  self._token = None # any cached token is invalid
167
169
  if "WWW-Authenticate" in response.http_response.headers:
168
- request_authorized = self.on_challenge(request, response)
170
+ try:
171
+ request_authorized = self.on_challenge(request, response)
172
+ except Exception as ex:
173
+ # If the response is streamed, read it so the error message is immediately available to the user.
174
+ # Otherwise, a generic error message will be given and the user will have to read the response
175
+ # body to see the actual error.
176
+ if response.context.options.get("stream"):
177
+ try:
178
+ response.http_response.read() # type: ignore
179
+ except Exception: # pylint:disable=broad-except
180
+ pass
181
+ # Raise the exception from the token request with the original 401 response
182
+ raise ex from HttpResponseError(response=response.http_response)
183
+
169
184
  if request_authorized:
170
185
  # if we receive a challenge response, we retrieve a new token
171
186
  # which matches the new target. In this case, we don't want to remove
@@ -200,14 +215,11 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
200
215
  encoded_claims = get_challenge_parameter(headers, "Bearer", "claims")
201
216
  if not encoded_claims:
202
217
  return False
203
- try:
204
- padding_needed = -len(encoded_claims) % 4
205
- claims = base64.urlsafe_b64decode(encoded_claims + "=" * padding_needed).decode("utf-8")
206
- if claims:
207
- self.authorize_request(request, *self._scopes, claims=claims)
208
- return True
209
- except Exception: # pylint:disable=broad-except
210
- return False
218
+ padding_needed = -len(encoded_claims) % 4
219
+ claims = base64.urlsafe_b64decode(encoded_claims + "=" * padding_needed).decode("utf-8")
220
+ if claims:
221
+ self.authorize_request(request, *self._scopes, claims=claims)
222
+ return True
211
223
  return False
212
224
 
213
225
  def on_response(