Skip to content

Cannot handle None in custom data dumper #377

@sakishrist

Description

@sakishrist

Python: 3.10.6
Psycopg: 3.0.16

I was handling dates with a custom Loader and Dumper with psycopg3:

class ExceptionDateDumper(DateDumper):
    def dump(self, obj):

        year = obj.year
        month = obj.month
        day = obj.day

        if year is None and month is None and day is None:
            return super().dump(None)

        if year < 0:
            bc = " BC"
            year*=-1
        else:
            bc = ""

        day = 1 if day is None else day
        month = 1 if month is None else month

        return bytes(f'{year:04}-{month:02}-{day:02}{bc}', encoding='utf-8')

I know the code is kinda sloppy, but the problem is that I cannot give None to super().dump()

Also if I do return b'\N' instead which should be the Postgres Null string, it gets converted to \\N when given to the DB (the rest of the null values that I do not try to mess with are still just \N so are handled fine by Postgres). So I assume it tries to escape my value that I pass while I though writing a Dumper like this would not try to do any further processing.

I also tried with \0 for good measure, but of course that didn't work.

In the end I ended up doing this:

#SQLDate is my custom type that I registered with `register_dumper`
date = None if year is None and month is None and day is None else SQLDate(year, month, day)

# Three dots just means more arguments
copy.write_row(   (..., date, ...)   )

I don't like this approach though as I handle None outside the DateDumper.

If I have missed something, hopefully with your help we can update the documentation to make this more clear how it should be handled.

Thank you so much for making this project! :)


EDIT:

I also have a __nonzero__ method in the custom type, but it does not change the handling.

class SQLDate:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    
    def __str__(self):
        return f'SQLDate({self.year:04}-{self.month:02}-{self.day:02})'

    def __nonzero__(self):
        if self.year is None and self.month is None and self.day is None:
            return False
        else:
            return True

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions