MagicStack / MagicStack/asyncpg
set_type_codec encoder to handle numpy/pandas null types not working with copy_records_to_table
Personne n'a encore pris cette issue.
- Langage dominant
- Python
- Étoiles
- 8.1k
- Forks
- 468
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
* **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](https://github.com/magicstack/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:
```sql
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:
```python
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:
```log
....
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:
```log
insufficient data left in message
````
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par les entrées de trace de pile de copy_in et Codec.encode dans asyncpg/protocol/protocol.pyx et asyncpg/protocol/codecs/base.pyx, puis examinez asyncpg/pgproto/./codecs/bytea.pyx. Reproduisez l’exemple de set_type_codec et copy_records_to_table avec des valeurs nulles de pandas et NumPy ; le travail est terminé lorsque le comportement nul attendu pour ce chemin est établi et couvert.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- numpy, pandas, postgresql, python
- Domaine
- databases
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- À clarifier
- Accessibilité débutants
- 25/100