New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pelican can't pickle cache: TypeError: can't pickle 'generator' object #2905
Comments
To be clear, there is no additional information when run with full debug tracing, and this happens without any plugins enabled:
|
Well, I don't see any generators there and I could not reproduce this on Win 8.1 Python 3.7. So I'm not sure how to investigate this. If you don't mind some debugging, you could throw some |
I tried debugging save_cache but it's just getting a normal dictionary. A dictionary goes into the pickler, and the pickler throws the error from a codespace I can't debug. It's very strange. Here's some debug code: def test_cache(obj):
if isinstance(obj, dict):
iterator = obj.items()
elif isinstance(obj, list) or isinstance(obj, tuple):
iterator = enumerate(obj)
for key, value in iterator:
if isinstance(value, dict):
test_cache(value)
elif isinstance(value, list) or isinstance(value, tuple):
test_cache(value)
else:
print(type(value), str(value)[:70])
...
class FileDataCacher:
...
def save_cache(self):
"""Save the updated cache"""
if self._cache_data_policy:
try:
mkdir_p(self.settings['CACHE_PATH'])
test_cache(self._cache)
with self._cache_open(self._cache_path, 'wb') as fhandle:
pickle.dump(self._cache, fhandle)
except (OSError, pickle.PicklingError) as err:
logger.warning('Could not save cache %s\n ... %s',
self._cache_path, err) And here's the output:
So there has to be a generator in one of those pelican objects, right? |
|
I don't think it was trying to load any caches before, but manually deleting the cache directory has the same result:
|
Installed Python 3.8.5 to see if that would make any difference, but no, still cannot reproduce here (win 8.1 though). (pelican) > pelican content -s pelicanconf.py
WARNING: Docutils has no localization for 'english'. Using 'en' instead.
WARNING: Watched path does not exist: D:\workspace\pelican-test\content\images
{'D:\\workspace\\pelican-test\\content\\article.md': (1628975297.942422, ('<p>Content</p>', {'title': 'test', 'date': SafeDatetime(2019, 1, 1, 0, 0), 'tags': [<Tag 'foo'>, <Tag 'bar'>], 'category': <Category 'Baz'>}))}
{}
Done: Processed 1 article, 0 drafts, 0 hidden articles, 0 pages, 0 hidden pages and 0 draft pages in 0.33 seconds. The dictionaries in the log are just me adding |
I know, it's bizarre. What other troubleshooting steps are there? I can't get pickle to tell me exactly what object it thinks is failing, either. The only thing I can identify is that this is the only case where pickling outputs this specific TypeError: # Python code for object.__reduce_ex__ for protocols 0 and 1
def _reduce_ex(self, proto):
assert proto < 2
cls = self.__class__
for base in cls.__mro__:
if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE:
break
else:
base = object # not really reachable
if base is object:
state = None
else:
if base is cls:
raise TypeError(f"cannot pickle {cls.__name__!r} object")
state = base(self)
args = (cls, base, state)
try:
getstate = self.__getstate__
except AttributeError:
if getattr(self, "__slots__", None):
raise TypeError(f"cannot pickle {cls.__name__!r} object: "
f"a class that defines __slots__ without "
f"defining __getstate__ cannot be pickled "
f"with protocol {proto}") from None
try:
dict = self.__dict__
except AttributeError:
dict = None
else:
dict = getstate()
if dict:
return _reconstructor, args, dict
else:
return _reconstructor, args If I patch in Yeah, I'm sorry that this doesn't make any sense, but if I could make sense of it this wouldn't be an issue. |
I am not getting these same errors on the blank sample project, so this has something to do with my configuration... somehow? Again, this doesn't make any sense to me, because something would have to be somehow injecting a generator into a pelican wrapper, which I don't think anything does. And I know it's not a plugin setting, because I can reproduce the issue exactly when all plugins are disabled. |
I found it. Buried deep in a subconfiguration file, pelicanconf was getting this in the main configuration namespace: LINKS = (link[:1] for link in INLINKS_EX + LINKS_EX) Now, how this got into the article generator cache I have no idea. Does SafeDatetime have a full copy of the pelican context or something? |
Oh... |
Might be worth adding a note to the caching documentation about avoiding the use of generators in pelicanconf. |
Perhaps generators and functions in the configuration file should only be folded into objects if their names are all uppercase, as the documentation suggests? |
Putting custom template functions into the pelicanconf tends to break the cache with pickle errors too. I ended up moving all my custom template functions out into a local plugin to get around this. |
You can get around a surprising amount of pickle errors by just putting jinja filters into a separate configuration file and doing from jinja_filters import * |
That's annoying and we should probably address that. I think |
I had a similar issue where Pelican was failing to Pickle a lambda function included in pelicanconf.py. Thanks for the hint @GiovanH ! |
Issue
When enabling caching on windows, Pelican is unable to save the caches as pickles because they apparently contain generators.
Cache configuration looks like
(Using #2904 to get output)
What's strange about this is there don't seem to actually be any generators in the cache. If I look at the
self._cache
objectsave_cache
is trying to pickle, it just looks like a map between filename strings and values like this:This doesn't seem to be a duplicate of #2400, as this has nothing to do with threading or watchers. It's just failing to pickle a boring object.
The text was updated successfully, but these errors were encountered: