1515
1616from pyproject_api ._util import ensure_empty_dir
1717
18+ if sys .version_info >= (3 , 8 ): # pragma: no cover (py38+)
19+ from typing import TypedDict
20+ else : # pragma: no cover (py38+)
21+ from typing_extensions import TypedDict
22+
1823if sys .version_info >= (3 , 11 ): # pragma: no cover (py311+)
1924 import tomllib
2025else : # pragma: no cover (py311+)
2429ConfigSettings = Optional [Dict [str , Any ]]
2530
2631
32+ class OptionalHooks (TypedDict , total = True ):
33+ """A flag indicating if the backend supports the optional hook or not"""
34+
35+ get_requires_for_build_sdist : bool
36+ prepare_metadata_for_build_wheel : bool
37+ get_requires_for_build_wheel : bool
38+ build_editable : bool
39+ get_requires_for_build_editable : bool
40+ prepare_metadata_for_build_editable : bool
41+
42+
2743class CmdStatus (ABC ):
2844 @property
2945 @abstractmethod
@@ -190,6 +206,7 @@ def __init__(
190206 self ._backend_obj = backend_obj
191207 self .requires : tuple [Requirement , ...] = requires
192208 self ._reuse_backend = reuse_backend
209+ self ._optional_hooks : OptionalHooks | None = None
193210
194211 @classmethod
195212 def create_args_from_folder (
@@ -243,17 +260,25 @@ def backend_args(self) -> list[str]:
243260 result .append (self ._backend_obj )
244261 return result
245262
263+ @property
264+ def optional_hooks (self ) -> OptionalHooks :
265+ """:return: a dictionary indicating if the optional hook is supported or not"""
266+ if self ._optional_hooks is None :
267+ result , _ , __ = self ._send ("_optional_hooks" )
268+ self ._optional_hooks = result
269+ return self ._optional_hooks
270+
246271 def get_requires_for_build_sdist (self , config_settings : ConfigSettings | None = None ) -> RequiresBuildSdistResult :
247272 """
248273 Get build requirements for a source distribution (per PEP-517).
249274
250275 :param config_settings: run arguments
251276 :return: outcome
252277 """
253- try :
278+ if self . optional_hooks [ "get_requires_for_build_sdist" ] :
254279 result , out , err = self ._send (cmd = "get_requires_for_build_sdist" , config_settings = config_settings )
255- except BackendFailed as exc :
256- result , out , err = [], exc . out , exc . err
280+ else :
281+ result , out , err = [], "" , ""
257282 if not isinstance (result , list ) or not all (isinstance (i , str ) for i in result ):
258283 self ._unexpected_response ("get_requires_for_build_sdist" , result , "list of string" , out , err )
259284 return RequiresBuildSdistResult (tuple (Requirement (r ) for r in cast (List [str ], result )), out , err )
@@ -265,10 +290,10 @@ def get_requires_for_build_wheel(self, config_settings: ConfigSettings | None =
265290 :param config_settings: run arguments
266291 :return: outcome
267292 """
268- try :
293+ if self . optional_hooks [ "get_requires_for_build_wheel" ] :
269294 result , out , err = self ._send (cmd = "get_requires_for_build_wheel" , config_settings = config_settings )
270- except BackendFailed as exc :
271- result , out , err = [], exc . out , exc . err
295+ else :
296+ result , out , err = [], "" , ""
272297 if not isinstance (result , list ) or not all (isinstance (i , str ) for i in result ):
273298 self ._unexpected_response ("get_requires_for_build_wheel" , result , "list of string" , out , err )
274299 return RequiresBuildWheelResult (tuple (Requirement (r ) for r in cast (List [str ], result )), out , err )
@@ -282,10 +307,10 @@ def get_requires_for_build_editable(
282307 :param config_settings: run arguments
283308 :return: outcome
284309 """
285- try :
310+ if self . optional_hooks [ "get_requires_for_build_editable" ] :
286311 result , out , err = self ._send (cmd = "get_requires_for_build_editable" , config_settings = config_settings )
287- except BackendFailed as exc :
288- result , out , err = [], exc . out , exc . err
312+ else :
313+ result , out , err = [], "" , ""
289314 if not isinstance (result , list ) or not all (isinstance (i , str ) for i in result ):
290315 self ._unexpected_response ("get_requires_for_build_editable" , result , "list of string" , out , err )
291316 return RequiresBuildEditableResult (tuple (Requirement (r ) for r in cast (List [str ], result )), out , err )
@@ -301,13 +326,13 @@ def prepare_metadata_for_build_wheel(
301326 :return: metadata generation result
302327 """
303328 self ._check_metadata_dir (metadata_directory )
304- try :
329+ if self . optional_hooks [ "prepare_metadata_for_build_wheel" ] :
305330 basename , out , err = self ._send (
306331 cmd = "prepare_metadata_for_build_wheel" ,
307332 metadata_directory = metadata_directory ,
308333 config_settings = config_settings ,
309334 )
310- except BackendFailed :
335+ else :
311336 # if backend does not provide it acquire it from the wheel
312337 basename , err , out = self ._metadata_from_built_wheel (config_settings , metadata_directory , "build_wheel" )
313338 if not isinstance (basename , str ):
@@ -333,13 +358,13 @@ def prepare_metadata_for_build_editable(
333358 :return: metadata generation result
334359 """
335360 self ._check_metadata_dir (metadata_directory )
336- try :
361+ if self . optional_hooks [ "prepare_metadata_for_build_editable" ] :
337362 basename , out , err = self ._send (
338363 cmd = "prepare_metadata_for_build_editable" ,
339364 metadata_directory = metadata_directory ,
340365 config_settings = config_settings ,
341366 )
342- except BackendFailed :
367+ else :
343368 # if backend does not provide it acquire it from the wheel
344369 basename , err , out = self ._metadata_from_built_wheel (config_settings , metadata_directory , "build_editable" )
345370 if not isinstance (basename , str ):
@@ -481,5 +506,5 @@ def _send(self, cmd: str, **kwargs: Any) -> tuple[Any, str, str]:
481506
482507 @abstractmethod
483508 @contextmanager
484- def _send_msg (self , cmd : str , result_file : Path , msg : str ) -> Iterator [CmdStatus ]: # noqa: U100
509+ def _send_msg (self , cmd : str , result_file : Path , msg : str ) -> Iterator [CmdStatus ]:
485510 raise NotImplementedError
0 commit comments