How to pickle and unpickle to portable string in Python 3

2024/11/20 20:20:20

I need to pickle a Python3 object to a string which I want to unpickle from an environmental variable in a Travis CI build. The problem is that I can't seem to find a way to pickle to a portable string (unicode) in Python3:

import os, pickle    from my_module import MyPickleableClassobj = {'cls': MyPickleableClass, 'other_stuf': '(...)'}pickled = pickle.dumps(obj)# raises TypeError: str expected, not bytes
os.environ['pickled'] = pickled# raises UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb (...)
os.environ['pickled'] = pickled.decode('utf-8')pickle.loads(os.environ['pickled'])

Is there a way to serialize complex objects like datetime.datetime to unicode or to some other string representation in Python3 which I can transfer to a different machine and deserialize?

Update

I have tested the solutions suggested by @kindall, but the pickle.dumps(obj, 0).decode() raises a UnicodeDecodeError. Nevertheless the base64 approach works but it needed an extra decode/encode step. The solution works on both Python2.x and Python3.x.

# encode returns bytes so it needs to be decoded to string
pickled = pickle.loads(codecs.decode(pickled.encode(), 'base64')).decode()type(pickled)  # <class 'str'>unpickled = pickle.loads(codecs.decode(pickled.encode(), 'base64'))
Answer

pickle.dumps() produces a bytes object. Expecting these arbitrary bytes to be valid UTF-8 text (the assumption you are making by trying to decode it to a string from UTF-8) is pretty optimistic. It'd be a coincidence if it worked!

One solution is to use the older pickling protocol that uses entirely ASCII characters. This still comes out as bytes, but since those bytes contain only ASCII code points, it can be converted to a string without stress:

pickled = str(pickle.dumps(obj, 0))

You could also use some other encoding method to encode a binary-pickled object to text, such as base64:

import codecs
pickled = codecs.encode(pickle.dumps(obj), "base64").decode()

Decoding would then be:

unpickled = pickle.loads(codecs.decode(pickled.encode(), "base64"))

Using pickle with protocol 0 seems to result in shorter strings than base64-encoding binary pickles (and abarnert's suggestion of hex-encoding is going to be even larger than base64), but I haven't tested it rigorously or anything. Test it with your data and see.

https://en.xdnf.cn/q/26282.html

Related Q&A

Using RabbitMQ is there a way to look at the queue contents without a dequeue operation?

As a way to learn RabbitMQ and python Im working on a project that allows me to distribute h264 encodes between a number of computers. The basics are done, I have a daemon that runs on Linux or Mac th…

Pip default behavior conflicts with virtualenv?

I was following this tutorial When I got to virtualenv flask command, I received this error message: Can not perform a --user install. User site-packages are not visible in this virtualenv.This makes s…

How to update user password in Django Rest Framework?

I want to ask that following code provides updating password but I want to update password after current password confirmation process. So what should I add for it? Thank you.class UserPasswordSeriali…

ImportError: No module named xlrd

I am currently using PyCharm with Python version 3.4.3 for this particular project.This PyCharm previously had Python2.7, and I upgraded to 3.4.3.I am trying to fetch data from an Excel file using Pand…

How do I automatically fix lint issues reported by pylint?

Just like we have "eslint --fix" to automatically fix lint problems in Javascript code, do we have something for pylint too for Python code?

Conversion from JavaScript to Python code? [closed]

Closed. This question is seeking recommendations for books, tools, software libraries, and more. It does not meet Stack Overflow guidelines. It is not currently accepting answers.We don’t allow questi…

connect to a DB using psycopg2 without password

I have a postgres database on my localhost I can access without a password$ psql -d mwt psql (8.4.12) Type "help" for help.mwt=# SELECT * from vatid;id | requester_vatid |...-----+---------…

Shebang doesnt work with python3

I have the following program:#!/usr/local/bin/python3print("Hello")Via terminal I do test.py and I get:Traceback (most recent call last):File "/usr/lib/python3.3/site.py", line 629,…

Why does pip freeze list pkg-resources==0.0.0?

On Ubuntu 16.04 with virtualenv 15.0.1 and Python 3.5.2 (both installed with apt) when I create and activate new Python virtual environment withvirtualenv .virtualenvs/wtf -p $(which python3) --no-site…

How to delete an instantiated object Python?

I am relatively new to object oriented programming and I cannot figure out how to delete an instantiated object in Python. if self.hit_paddle(pos) == True or self.hit_paddle2(pos) == True:bar = bar + 1…