Make Config picklable

This commit is contained in:
Takeshi KOMIYA 2018-05-10 00:43:48 +09:00
parent 169297d0b7
commit 0e2cb4793e
2 changed files with 34 additions and 13 deletions

View File

@ -11,12 +11,15 @@
import re
import traceback
import types
import warnings
from collections import OrderedDict
from os import path, getenv
from typing import Any, NamedTuple, Union
from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integer_types
from six import (
PY2, PY3, iteritems, string_types, binary_type, text_type, integer_types, class_types
)
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.errors import ConfigError, ExtensionError
@ -35,6 +38,7 @@ if False:
logger = logging.getLogger(__name__)
CONFIG_FILENAME = 'conf.py'
UNSERIALIZEABLE_TYPES = class_types + (types.ModuleType, types.FunctionType)
copyright_year_re = re.compile(r'^((\d{4}-)?)(\d{4})(?=[ ,])')
if PY3:
@ -308,6 +312,34 @@ class Config(object):
rebuild = [rebuild]
return (value for value in self if value.rebuild in rebuild)
def __getstate__(self):
# type: () -> Dict
"""Obtains serializable data for pickling."""
# remove potentially pickling-problematic values from config
__dict__ = {}
for key, value in iteritems(self.__dict__):
if key.startswith('_') or isinstance(value, UNSERIALIZEABLE_TYPES):
pass
else:
__dict__[key] = value
# create a picklable copy of values list
__dict__['values'] = {}
for key, value in iteritems(self.values): # type: ignore
real_value = getattr(self, key)
if isinstance(real_value, UNSERIALIZEABLE_TYPES):
# omit unserializable value
real_value = None
# types column is also omitted
__dict__['values'][key] = (real_value, value[1], None)
return __dict__
def __setstate__(self, state):
# type: (Dict) -> None
self.__dict__.update(state)
def eval_config_file(filename, tags):
# type: (unicode, Tags) -> Dict[unicode, Any]

View File

@ -12,14 +12,13 @@
import os
import re
import sys
import types
import warnings
from collections import defaultdict
from copy import copy
from os import path
from docutils.utils import Reporter, get_source_line
from six import BytesIO, class_types, next
from six import BytesIO, next
from six.moves import cPickle as pickle
from sphinx import addnodes
@ -126,21 +125,11 @@ class BuildEnvironment(object):
# remove unpicklable attributes
app = env.app
del env.app
values = env.config.values
del env.config.values
domains = env.domains
del env.domains
# remove potentially pickling-problematic values from config
for key, val in list(vars(env.config).items()):
if key.startswith('_') or \
isinstance(val, types.ModuleType) or \
isinstance(val, types.FunctionType) or \
isinstance(val, class_types):
del env.config[key]
pickle.dump(env, f, pickle.HIGHEST_PROTOCOL)
# reset attributes
env.domains = domains
env.config.values = values
env.app = app
@classmethod