If you don't have access to COPY if the postgres instance is managed, I've had a lot of luck with encoding a batch of rows as a JSON string, sending the string as a single query parameter, and using `json_to_recordset` to turn the JSON back into a list of rows in the db.
I haven't compared how this performs compared to using a low-level sql library but it outperforms everything else I've tried in sqlalchemy.