J'ai rencontré un problème similaire et après quelques heures de sang, de sueur et de larmes, j'ai trouvé que la réponse nécessitait simplement l'ajout d'un paramètre.
Au lieu de
cursor = conn.cursor()
écrire
cursor = conn.cursor(name="my_cursor_name")
ou plus simple encore
cursor = conn.cursor("my_cursor_name")
Les détails se trouvent à http://initd.org/psycopg/docs/usage.html#server-side-cursors
J'ai trouvé les instructions un peu déroutantes dans la mesure où je pensais devoir réécrire mon SQL pour inclure "DECLARE my_cursor_name ...." puis un "FETCH count 2000 FROM my_cursor_name" mais il s'avère que psycopg fait tout cela pour vous sous le capot si vous écrasez simplement le paramètre par défaut "name=None" lors de la création d'un curseur.
La suggestion ci-dessus d'utiliser fetchone ou fetchmany ne résout pas le problème car, si vous laissez le paramètre de nom non défini, psycopg tentera par défaut de charger la requête entière dans la RAM. La seule autre chose dont vous pourriez avoir besoin (en plus de déclarer un paramètre de nom) est de changer l'attribut cursor.itersize de la valeur par défaut 2000 à dire 1000 si vous avez encore trop peu de mémoire.