Как я могу предотвратить Java-библиотеки от загрязнения STDOUT - PullRequest
1 голос
/ 20 мая 2019

Я пишу программу на python 3.6, которая использует pyspark для некоторых вычислений. Я пишу это так, чтобы она могла вести себя как правильная программа UNIX, принимая входные данные из STDIN и передавая выходные данные в STDOUT.

Java не поддерживается, и языком по умолчанию является выход в STDOUT при достаточно высокой степени серьезности журнала. pyspark не привыкать к этому.

Нужно ли мне вручную связываться с дескрипторами файлов перед импортом какой-либо библиотеки py4j, или есть какой-то способ манипулирования java-компонентом со стороны Python, чтобы вся запись шла в STDERR?

Один клудж, который я ожидал сработать, но в основном это не так это :

import contextlib
import sys

@contextlib.contextmanager
def impolite_library_wrapper():
    real_out = sys.stdout
    sys.stdout = sys.stderr
    yield
    sys.stdout = real_out

with impolite_library_wrapper():
    import pyspark.sql
    spark_builder = pyspark.sql.SparkSession.builder.enableHiveSupport()
    spark = spark_builder.getOrCreate()

print("pls")

... который я могу запустить в минимальной среде, например:

$ bash
$ mkdir /tmp/pls
$ cd /tmp/pls
$ pipenv install pyspark==2.3
$ env -i "PATH=$PATH" pipenv run python wtf.py 2>/dev/null
2019-05-20 17:10:54 WARN  Utils:66 - Your hostname, <redacted> resolves to a loopback address...
2019-05-20 17:10:54 WARN  Utils:66 - Set SPARK_LOCAL_IP if you need to bind to another address
2019-05-20 17:10:55 WARN  NativeCodeLoader:62 - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
pls

Я ожидал, что это выдаст pls и только pls.

Я вижу, что pyspark специально решит эту проблему с SPARK-21094 в Spark 3.0; Я мог бы жить с конкретным ответом на pyspark, но сейчас я нацеливаюсь на Spark 2.3.

1 Ответ

1 голос
/ 21 мая 2019

Я ненавижу каждую часть этого, но это, кажется, работает:

import contextlib
import sys
import subprocess

class StderrOnlyPopen(subprocess.Popen):
    def __init__(self, args, bufsize=-1, executable=None,
                 stdin=None, stdout=sys.stderr, *more, **kwmore):
        super().__init__(args, bufsize, executable,
                         stdin, stdout, *more, **kwmore)

@contextlib.contextmanager
def impolite_library_wrapper():
    real_Popen = subprocess.Popen
    subprocess.Popen = StderrOnlyPopen
    yield
    subprocess.Popen = real_Popen

with impolite_library_wrapper():
    import pyspark.sql

spark_builder = pyspark.sql.SparkSession.builder.enableHiveSupport()
spark = spark_builder.getOrCreate()
...