Skip to content

Commit fbdd8b3

Browse files
authored
Merge pull request #34304 Better error messages for unavailable providers.
2 parents 8a418f5 + c7d67a8 commit fbdd8b3

File tree

3 files changed

+50
-10
lines changed

3 files changed

+50
-10
lines changed

sdks/python/apache_beam/yaml/yaml_provider.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from collections.abc import Mapping
3838
from typing import Any
3939
from typing import Optional
40+
from typing import Union
4041

4142
import docstring_parser
4243
import yaml
@@ -65,9 +66,21 @@
6566
from 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+
6881
class 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()]

sdks/python/apache_beam/yaml/yaml_transform.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,26 @@ def best_provider(
237237
spec = t
238238
else:
239239
spec = self._transforms_by_uuid[self.get_transform_id(t)]
240-
possible_providers = [
241-
p for p in self.providers[spec['type']] if p.available()
242-
]
240+
possible_providers = []
241+
unavailable_provider_messages = []
242+
for p in self.providers[spec['type']]:
243+
is_available = p.available()
244+
if is_available:
245+
possible_providers.append(p)
246+
else:
247+
reason = getattr(is_available, 'reason', 'no reason given')
248+
unavailable_provider_messages.append(
249+
f'{p.__class__.__name__} ({reason})')
243250
if not possible_providers:
251+
if unavailable_provider_messages:
252+
unavailable_provider_message = (
253+
'\nThe following providers were found but not available: ' +
254+
'\n'.join(unavailable_provider_messages))
255+
else:
256+
unavailable_provider_message = ''
244257
raise ValueError(
245-
'No available provider for type %r at %s' %
246-
(spec['type'], identify_object(spec)))
258+
'No available provider for type %r at %s%s' %
259+
(spec['type'], identify_object(spec), unavailable_provider_message))
247260
# From here on, we have the invariant that possible_providers is not empty.
248261

249262
# Only one possible provider, no need to rank further.

sdks/python/apache_beam/yaml/yaml_transform_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ def test_strip_error_metadata(self):
534534
config:
535535
language: python
536536
fields:
537-
out: "1/(1-len(element))"
537+
out: "1.0/(1-len(element))"
538538
error_handling:
539539
output: errors
540540
- type: StripErrorMetadata

0 commit comments

Comments
 (0)