Почему режим файла отличается при использовании open()
по сравнению с gzip.open()
из официального модуля gzip?
Python 2.7 в Linux.
То же самое происходит при использовании GzipFile
для уже открытого дескриптора файла.
Я думал, что он должен быть прозрачным, так почему же я вижу числовые режимы, а не rb
/ wb
?
Тестовый сценарий
#!/usr/bin/env python
"""
Write one file to another, with optional gzip on both sides.
Usage:
gzipcat.py <input file> <output file>
Examples:
gzipcat.py /etc/passwd passwd.bak.gz
gzipcat.py passwd.bak.gz passwd.bak
"""
import sys
import gzip
if len(sys.argv) < 3:
sys.exit(__doc__)
ifn = sys.argv[1]
if ifn.endswith('.gz'):
ifd = gzip.open(ifn, 'rb')
else:
ifd = open(ifn, 'rb')
ofn = sys.argv[2]
if ofn.endswith('.gz'):
ofd = gzip.open(ofn, 'wb')
else:
ofd = open(ofn, 'wb')
ifm = getattr(ifd, 'mode', None)
ofm = getattr(ofd, 'mode', None)
print('input file mode: {}, output file mode: {}'.format(ifm, ofm))
for ifl in ifd:
ofd.write(ifl)
Вывод тестового сценария
$ python gzipcat.py /etc/passwd passwd.bak
input file mode: rb, output file mode: wb
$ python gzipcat.py /etc/passwd passwd.bak.gz
input file mode: rb, output file mode: 2
$ python gzipcat.py passwd.bak.gz passwd.txt
input file mode: 1, output file mode: wb
$ python gzipcat.py passwd.bak.gz passwd.txt.gz
input file mode: 1, output file mode: 2
Дополнительный вопрос: есть ли для этого какая-то веская причина, или это просто упущение/необработанный случай в модуле gzip?
Фон
На самом деле я использую загрузчик Google BigQuery, который требует, чтобы режим был rb
, прежде чем использовать его в качестве источника данных. Трассировка ниже. Но я подготовил минимальный тестовый пример выше, чтобы сделать этот вопрос более читабельным.
# python -c 'import etl; etl.job001()'
Starting job001.
Processing table: reviews.
Extracting reviews, time range [2018-04-07 17:01:38.172129+00:00, 2018-04-07 18:09:50.763283)
Extracted 24 rows to reviews.tmp.gz in 2 s (8 rows/s).
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "etl.py", line 920, in wf_dimension_tables
ts_end=ts_end)
File "etl.py", line 680, in map_table_delta
rewrite=True
File "etl.py", line 624, in bq_load_csv
job_config=job_config)
File "/usr/lib/python2.7/site-packages/google/cloud/bigquery/client.py", line 797, in load_table_from_file
_check_mode(file_obj)
File "/usr/lib/python2.7/site-packages/google/cloud/bigquery/client.py", line 1419, in _check_mode
"Cannot upload files opened in text mode: use "
ValueError: Cannot upload files opened in text mode: use open(filename, mode='rb') or open(filename, mode='r+b')
А вот вызов API bigquery, который использует дескриптор файла:
def bq_load_csv(dataset_id, table_id, fileobj):
client = bigquery.Client()
dataset_ref = client.dataset(dataset_id)
table_ref = dataset_ref.table(table_id)
job_config = bigquery.LoadJobConfig()
job_config.source_format = 'text/csv'
job_config.field_delimiter = ','
job_config.skip_leading_rows = 0
job_config.allow_quoted_newlines = True
job_config.max_bad_records = 0
job = client.load_table_from_file(
fileobj,
table_ref,
job_config=job_config)
res = job.result() # Waits for job to complete
return res
Обновление
Эта проблема была исправлена в клиенте python bigquery 1.5.0. Спасибо @a-queue, отправившему отчет об ошибке, и разработчикам Google, которые ее исправили.
Можете ли вы поделиться кодом, который вы используете для загрузки в bq?
@WillianFuks, весь код? к сожалению нет. Это просто Python API для BQ, который задокументирован здесь: googlecloudplatform.github.io/google-cloud-python/latest/… Если у вас есть какие-либо конкретные вопросы об использовании клиентского кода BQ, я с радостью отвечу, пожалуйста. вставьте их на SO и дайте мне ссылку здесь. Мой вопрос заключается в том, почему свойство режима не работает в gzip.open.
@WillianFuks Я добавил вызов API bigquery, который вызывает исключение, помогает ли это?