3737from collections .abc import Mapping
3838from typing import Any
3939from typing import Optional
40+ from typing import Union
4041
4142import docstring_parser
4243import yaml
6566from apache_beam .yaml .yaml_errors import maybe_with_exception_handling_transform_fn
6667
6768
69+ class NotAvailableWithReason :
70+ """A False value that provides additional content.
71+
72+ Primarily used to return a value from Provider.available().
73+ """
74+ def __init__ (self , reason ):
75+ self .reason = reason
76+
77+ def __bool__ (self ):
78+ return False
79+
80+
6881class Provider :
6982 """Maps transform types names and args to concrete PTransform instances."""
70- def available (self ) -> bool :
83+ def available (self ) -> Union [ bool , NotAvailableWithReason ] :
7184 """Returns whether this provider is available to use in this environment."""
7285 raise NotImplementedError (type (self ))
7386
@@ -308,6 +321,7 @@ class RemoteProvider(ExternalProvider):
308321
309322 def __init__ (self , urns , address : str ):
310323 super ().__init__ (urns , service = address )
324+ self ._address = address
311325
312326 def available (self ):
313327 if self ._is_available is None :
@@ -316,7 +330,8 @@ def available(self):
316330 service .ready (1 )
317331 self ._is_available = True
318332 except Exception :
319- self ._is_available = False
333+ self ._is_available = NotAvailableWithReason (
334+ f'Remote provider not reachable at { self ._address } .' )
320335 return self ._is_available
321336
322337 def cache_artifacts (self ):
@@ -331,8 +346,20 @@ def __init__(self, urns, jar_provider):
331346
332347 def available (self ):
333348 # pylint: disable=subprocess-run-check
334- return subprocess .run (['which' , 'java' ],
335- capture_output = True ).returncode == 0
349+ trial = subprocess .run (['which' , 'java' ], capture_output = True )
350+ if trial .returncode == 0 :
351+ return True
352+ else :
353+
354+ def try_decode (bs ):
355+ try :
356+ return bs .decode ()
357+ except UnicodeError :
358+ return bs
359+
360+ return NotAvailableWithReason (
361+ f'Unable to locate java executable: '
362+ f'{ try_decode (trial .stdout )} { try_decode (trial .stderr )} ' )
336363
337364 def cache_artifacts (self ):
338365 return [self ._jar_provider ()]
0 commit comments