MagicStack / MagicStack/asyncpg

set_type_codec encoder to handle numpy/pandas null types not working with copy_records_to_table

オープン
#693 コメント 3 件 リアクション 1 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
Python
スター
8.1k
フォーク
468
PR マージ指標
30日以内にマージされた PR はありません

説明

  • asyncpg version:0.21.0
  • PostgreSQL version: PostgreSQL 13.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
  • Do you use a PostgreSQL SaaS? If so, which? Can you reproduce
    the issue with a local PostgreSQL install?
    :
  • Python version: 3.7
  • Platform: Ubuntu 18.04
  • Do you use pgbouncer?: no
  • Did you install asyncpg with pip?: yes
  • If you built asyncpg locally, which version of Cython did you use?: -
  • Can the issue be reproduced under both asyncio and
    uvloop?
    : -

I am trying to set up an asyncpg in order to use copy_records_to_table method passing pandas data frame, converted to list of lists.

My table is simple:

create table sg.test("no" int4, dt timestmap)

As pandas/numpy have their own Null types for different types (pd.NaT for dates and np.nan for numerics) I tried to set up an appropriate encoder:

import asyncio
import asyncpg
import pandas as pd
import numpy as np


data = [[1, np.datetime64('NaT')]]
df = pd.DataFrame(data=data, columns=["no", "dt"])


def encoder(val):
    if isinstance(val, (type(pd.NaT), type(np.nan))):
        return None
    return bytes(val)


def decoder(val): # we do not need that for this task
    return val


async def main(df: pd.DataFrame):

    conn: asyncpg.Connection=await asyncpg.connect('postgresql://connection_string')

    try:
        await conn.set_type_codec(
            'timestamp',
            encoder=encoder,
            decoder=decoder,
            schema='pg_catalog',
            format='binary'
        )
        res=await conn.copy_records_to_table('test', records=df.values.tolist(), columns=df.columns.values.tolist(), schema_name='sg')
        print(res)
    except ValueError as e:
        print(e.args)
    finally:
        await conn.close()

asyncio.get_event_loop().run_until_complete(main(df))

I am getting following error:

....
  File "asyncpg/protocol/protocol.pyx", line 482, in copy_in
  File "asyncpg/protocol/protocol.pyx", line 429, in asyncpg.protocol.protocol.BaseProtocol.copy_in
  File "asyncpg/protocol/codecs/base.pyx", line 192, in asyncpg.protocol.protocol.Codec.encode
  File "asyncpg/protocol/codecs/base.pyx", line 178, in asyncpg.protocol.protocol.Codec.encode_in_python
  File "asyncpg/pgproto/./codecs/bytea.pyx", line 19, in asyncpg.pgproto.pgproto.bytea_encode
TypeError: a bytes-like object is required, not 'NoneType'

For me it is unclear what kind of bytes should encoder return in case of Null value, I have tried to investigate it backwards: select a null value from original table with custom decoder, but it seems that asyncpg just amends that method in case of null values at all. So it is still unclear what kind of data should be passed.

I have already tried to return following values at encoder:

  • b''
  • b'\x01'
    another error occurs:
insufficient data left in message

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

asyncpg/protocol/protocol.pyx と asyncpg/protocol/codecs/base.pyx にある copy_in と Codec.encode のスタックトレースエントリから始め、次に asyncpg/pgproto/./codecs/bytea.pyx を調べます。pandas と NumPy の null 値を使って set_type_codec と copy_records_to_table の例を再現します。このパスで期待される null の動作が確立され、カバーされれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
numpy, pandas, postgresql, python
領域
databases
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
説明が足りない
初心者へのやさしさ
25/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。