Skip to content

Commit 2729aa6

Browse files
committed
Use DataprocCommandRunner to run "pip install"
1 parent 65fd706 commit 2729aa6

2 files changed

Lines changed: 26 additions & 27 deletions

File tree

google/cloud/dataproc_magics/magics.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
@magics_class
2626
class DataprocMagics(Magics):
2727

28+
PIP_INSTALL_FAILURE_MSG = "Pip install failed with non-zero exit code"
29+
DATAPROC_COMMAND_RUNNER = (
30+
"org.apache.spark.sql.artifact.DataprocCommandRunner"
31+
)
32+
PIP_INSTALL_COMMAND = "PipInstallPackages"
33+
2834
def __init__(
2935
self,
3036
shell,
@@ -45,9 +51,7 @@ def dpip(self, line):
4551
print(f"Installing packages: {packages}")
4652
output = self._run_command(packages, session)
4753

48-
failure_match = re.search(
49-
"Pip install failed with non-zero exit code", output
50-
)
54+
failure_match = re.search(self.PIP_INSTALL_FAILURE_MSG, output)
5155
if failure_match:
5256
raise RuntimeError(output)
5357

@@ -89,10 +93,8 @@ def _check_preconditions(self, args):
8993

9094
def _run_command(self, packages, session):
9195
command = pb2.Command()
92-
command.execute_external_command.runner = (
93-
"org.apache.spark.sql.artifact.DataprocCommandRunner"
94-
)
95-
command.execute_external_command.command = "PipInstallPackages"
96+
command.execute_external_command.runner = self.DATAPROC_COMMAND_RUNNER
97+
command.execute_external_command.command = self.PIP_INSTALL_COMMAND
9698

9799
for index, package in enumerate(packages):
98100
command.execute_external_command.options[str(index)] = package
@@ -104,9 +106,7 @@ def _run_command(self, packages, session):
104106

105107
# decode the Arrow stream and return the output
106108
table = pa.ipc.RecordBatchStreamReader(binary_data).read_all()
107-
return "\n".join(
108-
str(log_line) for log_line in table.column(0).to_pylist()
109-
)
109+
return "\n".join(table.column(0).to_pylist())
110110
except (KeyError, AttributeError) as e:
111111
raise RuntimeError(
112112
"Unexpected response structure: missing binary data."

tests/unit/dataproc_magics/test_magics.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ def setUp(self):
3333
self.shell.config = Config()
3434
self.magics = DataprocMagics(shell=self.shell)
3535

36+
def _create_mock_arrow_binary(self, lines: list[str]) -> bytes:
37+
schema = pa.schema([pa.field("output", pa.string())])
38+
table = pa.Table.from_arrays([lines], schema=schema)
39+
sink = pa.BufferOutputStream()
40+
with pa.ipc.RecordBatchStreamWriter(sink, table.schema) as writer:
41+
writer.write_table(table)
42+
return sink.getvalue()
43+
3644
def test_dpip_with_flags(self):
3745
with self.assertRaisesRegex(
3846
RuntimeError, "Error: Flags are not currently supported."
@@ -82,13 +90,9 @@ def test_dpip_install_packages_success(self):
8290
properties = mock.Mock()
8391

8492
# Create a pyarrow table and serialize it
85-
schema = pa.schema([pa.field("output", pa.string())])
86-
data = [["Collecting pandas", "Successfully installed pandas"]]
87-
table = pa.Table.from_arrays(data, schema=schema)
88-
sink = pa.BufferOutputStream()
89-
with pa.ipc.RecordBatchStreamWriter(sink, table.schema) as writer:
90-
writer.write_table(table)
91-
binary_data = sink.getvalue()
93+
binary_data = self._create_mock_arrow_binary(
94+
["Collecting pandas", "Successfully installed pandas"]
95+
)
9296

9397
# Set up the mock response structure
9498
properties.sql_command_result.local_relation.data = binary_data
@@ -109,7 +113,8 @@ def test_dpip_install_packages_success(self):
109113
call_args = mock_session.client.execute_command.call_args[0][0]
110114
self.assertIsInstance(call_args, pb2.Command)
111115
self.assertEqual(
112-
call_args.execute_external_command.command, "PipInstallPackages"
116+
call_args.execute_external_command.command,
117+
DataprocMagics.PIP_INSTALL_COMMAND,
113118
)
114119
self.assertEqual(
115120
call_args.execute_external_command.options["0"], "pandas"
@@ -130,18 +135,12 @@ def test_dpip_install_failure(self):
130135

131136
# Create a mock for the properties object with failure message
132137
properties = mock.Mock()
133-
schema = pa.schema([pa.field("output", pa.string())])
134-
data = [
138+
binary_data = self._create_mock_arrow_binary(
135139
[
136-
"Pip install failed with non-zero exit code",
140+
DataprocMagics.PIP_INSTALL_FAILURE_MSG,
137141
"ERROR: some pip error",
138142
]
139-
]
140-
table = pa.Table.from_arrays(data, schema=schema)
141-
sink = pa.BufferOutputStream()
142-
with pa.ipc.RecordBatchStreamWriter(sink, table.schema) as writer:
143-
writer.write_table(table)
144-
binary_data = sink.getvalue()
143+
)
145144

146145
properties.sql_command_result.local_relation.data = binary_data
147146
mock_session.client.execute_command.return_value = (

0 commit comments

Comments
 (0)