Skip to content

Commit c7bec75

Browse files
committed
BuildEnvironment always own application object (after read phase)
1 parent a523f98 commit c7bec75

File tree

5 files changed

+50
-55
lines changed

5 files changed

+50
-55
lines changed

sphinx/application.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,15 +301,15 @@ def _init_source_parsers(self):
301301
def _init_env(self, freshenv):
302302
# type: (bool) -> None
303303
if freshenv:
304-
self.env = BuildEnvironment(self.srcdir, self.doctreedir, self.config)
304+
self.env = BuildEnvironment(self)
305305
self.env.find_files(self.config, self.buildername)
306306
for domain in self.domains.keys():
307307
self.env.domains[domain] = self.domains[domain](self.env)
308308
else:
309309
try:
310310
logger.info(bold('loading pickled environment... '), nonl=True)
311-
self.env = BuildEnvironment.frompickle(
312-
self.srcdir, self.config, path.join(self.doctreedir, ENV_PICKLE_FILENAME))
311+
filename = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
312+
self.env = BuildEnvironment.frompickle(filename, self)
313313
self.env.domains = {}
314314
for domain in self.domains.keys():
315315
# this can raise if the data version doesn't fit
@@ -372,6 +372,7 @@ def build(self, force_all=False, filenames=None):
372372
else:
373373
self.emit('build-finished', None)
374374
self.builder.cleanup()
375+
self.env = None # clear environment
375376

376377
# ---- logging handling ----------------------------------------------------
377378
def warn(self, message, location=None, prefix=None,

sphinx/builders/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,7 @@ def build(self, docnames, summary=None, method='update'):
289289

290290
# while reading, collect all warnings from docutils
291291
with logging.pending_warnings():
292-
updated_docnames = set(self.env.update(self.config, self.srcdir,
293-
self.doctreedir, self.app))
292+
updated_docnames = set(self.env.update(self.config, self.srcdir, self.doctreedir))
294293

295294
doccount = len(updated_docnames)
296295
logger.info(bold('looking for now-outdated files... '), nonl=1)

sphinx/environment/__init__.py

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -104,33 +104,36 @@ class BuildEnvironment(object):
104104
# --------- ENVIRONMENT PERSISTENCE ----------------------------------------
105105

106106
@staticmethod
107-
def load(f, srcdir=None, config=None):
108-
# type: (IO, unicode, Config) -> BuildEnvironment
107+
def load(f, app=None):
108+
# type: (IO, Sphinx) -> BuildEnvironment
109109
env = pickle.load(f)
110110
if env.version != ENV_VERSION:
111111
raise IOError('build environment version not current')
112-
if srcdir and env.srcdir != srcdir:
113-
raise IOError('source directory has changed')
114-
if config:
115-
env.config.values = config.values
112+
if app:
113+
env.app = app
114+
env.config.values = app.config.values
115+
if env.srcdir != app.srcdir:
116+
raise IOError('source directory has changed')
116117
return env
117118

118119
@classmethod
119-
def loads(cls, string, srcdir=None, config=None):
120-
# type: (unicode, unicode, Config) -> BuildEnvironment
120+
def loads(cls, string, app=None):
121+
# type: (unicode, Sphinx) -> BuildEnvironment
121122
io = StringIO(string)
122-
return cls.load(io)
123+
return cls.load(io, app)
123124

124125
@classmethod
125-
def frompickle(cls, srcdir, config, filename):
126-
# type: (unicode, Config, unicode) -> BuildEnvironment
126+
def frompickle(cls, filename, app):
127+
# type: (unicode, Sphinx) -> BuildEnvironment
127128
with open(filename, 'rb') as f:
128-
return cls.load(f, srcdir, config)
129+
return cls.load(f, app)
129130

130131
@staticmethod
131132
def dump(env, f):
132133
# type: (BuildEnvironment, IO) -> None
133134
# remove unpicklable attributes
135+
app = env.app
136+
del env.app
134137
values = env.config.values
135138
del env.config.values
136139
domains = env.domains
@@ -146,6 +149,7 @@ def dump(env, f):
146149
# reset attributes
147150
env.domains = domains
148151
env.config.values = values
152+
env.app = app
149153

150154
@classmethod
151155
def dumps(cls, env):
@@ -161,19 +165,17 @@ def topickle(self, filename):
161165

162166
# --------- ENVIRONMENT INITIALIZATION -------------------------------------
163167

164-
def __init__(self, srcdir, doctreedir, config):
165-
# type: (unicode, unicode, Config) -> None
166-
self.doctreedir = doctreedir
167-
self.srcdir = srcdir # type: unicode
168-
self.config = config # type: Config
168+
def __init__(self, app):
169+
# type: (Sphinx) -> None
170+
self.app = app
171+
self.doctreedir = app.doctreedir
172+
self.srcdir = app.srcdir
173+
self.config = app.config
169174

170175
# the method of doctree versioning; see set_versioning_method
171176
self.versioning_condition = None # type: Union[bool, Callable]
172177
self.versioning_compare = None # type: bool
173178

174-
# the application object; only set while update() runs
175-
self.app = None # type: Sphinx
176-
177179
# all the registered domains, set by the application
178180
self.domains = {}
179181

@@ -490,8 +492,8 @@ def get_outdated_files(self, config_changed):
490492

491493
return added, changed, removed
492494

493-
def update(self, config, srcdir, doctreedir, app):
494-
# type: (Config, unicode, unicode, Sphinx) -> List[unicode]
495+
def update(self, config, srcdir, doctreedir):
496+
# type: (Config, unicode, unicode) -> List[unicode]
495497
"""(Re-)read all files new or changed since last update.
496498
497499
Store all environment docnames in the canonical format (ie using SEP as
@@ -519,7 +521,7 @@ def update(self, config, srcdir, doctreedir, app):
519521
# the source and doctree directories may have been relocated
520522
self.srcdir = srcdir
521523
self.doctreedir = doctreedir
522-
self.find_files(config, app.buildername)
524+
self.find_files(config, self.app.buildername)
523525
self.config = config
524526

525527
# this cache also needs to be updated every time
@@ -530,7 +532,7 @@ def update(self, config, srcdir, doctreedir, app):
530532
added, changed, removed = self.get_outdated_files(config_changed)
531533

532534
# allow user intervention as well
533-
for docs in app.emit('env-get-outdated', self, added, changed, removed):
535+
for docs in self.app.emit('env-get-outdated', self, added, changed, removed):
534536
changed.update(set(docs) & self.found_docs)
535537

536538
# if files were added or removed, all documents with globbed toctrees
@@ -543,23 +545,21 @@ def update(self, config, srcdir, doctreedir, app):
543545
len(removed))
544546
logger.info(msg)
545547

546-
self.app = app
547-
548548
# clear all files no longer present
549549
for docname in removed:
550-
app.emit('env-purge-doc', self, docname)
550+
self.app.emit('env-purge-doc', self, docname)
551551
self.clear_doc(docname)
552552

553553
# read all new and changed files
554554
docnames = sorted(added | changed)
555555
# allow changing and reordering the list of docs to read
556-
app.emit('env-before-read-docs', self, docnames)
556+
self.app.emit('env-before-read-docs', self, docnames)
557557

558558
# check if we should do parallel or serial read
559559
par_ok = False
560-
if parallel_available and len(docnames) > 5 and app.parallel > 1:
560+
if parallel_available and len(docnames) > 5 and self.app.parallel > 1:
561561
par_ok = True
562-
for extname, md in app._extension_metadata.items():
562+
for extname, md in self.app._extension_metadata.items():
563563
ext_ok = md.get('parallel_read_safe')
564564
if ext_ok:
565565
continue
@@ -575,17 +575,15 @@ def update(self, config, srcdir, doctreedir, app):
575575
par_ok = False
576576
break
577577
if par_ok:
578-
self._read_parallel(docnames, app, nproc=app.parallel)
578+
self._read_parallel(docnames, self.app, nproc=self.app.parallel)
579579
else:
580-
self._read_serial(docnames, app)
580+
self._read_serial(docnames, self.app)
581581

582582
if config.master_doc not in self.all_docs:
583583
raise SphinxError('master file %s not found' %
584584
self.doc2path(config.master_doc))
585585

586-
self.app = None
587-
588-
for retval in app.emit('env-updated', self):
586+
for retval in self.app.emit('env-updated', self):
589587
if retval is not None:
590588
docnames.extend(retval)
591589

@@ -608,20 +606,17 @@ def _read_parallel(self, docnames, app, nproc):
608606
self.clear_doc(docname)
609607

610608
def read_process(docs):
611-
# type: (List[unicode]) -> BuildEnvironment
609+
# type: (List[unicode]) -> unicode
612610
self.app = app
613611
for docname in docs:
614612
self.read_doc(docname, app)
615613
# allow pickling self to send it back
616-
del self.app
617-
del self.domains
618-
del self.config.values
619-
del self.config
620-
return self
614+
return BuildEnvironment.dumps(self)
621615

622616
def merge(docs, otherenv):
623-
# type: (List[unicode], BuildEnvironment) -> None
624-
self.merge_info_from(docs, otherenv, app)
617+
# type: (List[unicode], unicode) -> None
618+
env = BuildEnvironment.loads(otherenv)
619+
self.merge_info_from(docs, env, app)
625620

626621
tasks = ParallelTasks(nproc)
627622
chunks = make_chunks(docnames, nproc)

tests/test_environment.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def teardown_module():
3131
# afford to not run update() in the setup but in its own test
3232

3333
def test_first_update():
34-
updated = env.update(app.config, app.srcdir, app.doctreedir, app)
34+
updated = env.update(app.config, app.srcdir, app.doctreedir)
3535
assert set(updated) == env.found_docs == set(env.all_docs)
3636
# test if exclude_patterns works ok
3737
assert 'subdir/excluded' not in env.found_docs
@@ -71,7 +71,7 @@ def test_second_update():
7171
# the contents.txt toctree; otherwise section numbers would shift
7272
(root / 'autodoc.txt').unlink()
7373
(root / 'new.txt').write_text('New file\n========\n')
74-
updated = env.update(app.config, app.srcdir, app.doctreedir, app)
74+
updated = env.update(app.config, app.srcdir, app.doctreedir)
7575
# "includes" and "images" are in there because they contain references
7676
# to nonexisting downloadable or image files, which are given another
7777
# chance to exist
@@ -87,15 +87,15 @@ def on_env_read_docs_1(app, env, docnames):
8787

8888
app.connect('env-before-read-docs', on_env_read_docs_1)
8989

90-
read_docnames = env.update(app.config, app.srcdir, app.doctreedir, app)
90+
read_docnames = env.update(app.config, app.srcdir, app.doctreedir)
9191
assert len(read_docnames) > 2 and read_docnames == sorted(read_docnames)
9292

9393
def on_env_read_docs_2(app, env, docnames):
9494
docnames.remove('images')
9595

9696
app.connect('env-before-read-docs', on_env_read_docs_2)
9797

98-
read_docnames = env.update(app.config, app.srcdir, app.doctreedir, app)
98+
read_docnames = env.update(app.config, app.srcdir, app.doctreedir)
9999
assert len(read_docnames) == 2
100100

101101

tests/test_intl.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ def test_gettext_buildr_ignores_only_directive(app):
497497
def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo):
498498
# --- don't rebuild by .mo mtime
499499
def get_number_of_update_targets(app_):
500-
updated = app_.env.update(app_.config, app_.srcdir, app_.doctreedir, app_)
500+
updated = app_.env.update(app_.config, app_.srcdir, app_.doctreedir)
501501
return len(updated)
502502

503503
# setup new directory
@@ -680,12 +680,12 @@ def test_html_rebuild_mo(app):
680680
app.build()
681681
# --- rebuild by .mo mtime
682682
app.builder.build_update()
683-
updated = app.env.update(app.config, app.srcdir, app.doctreedir, app)
683+
updated = app.env.update(app.config, app.srcdir, app.doctreedir)
684684
assert len(updated) == 0
685685

686686
mtime = (app.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo').stat().st_mtime
687687
(app.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo').utime((mtime + 5, mtime + 5))
688-
updated = app.env.update(app.config, app.srcdir, app.doctreedir, app)
688+
updated = app.env.update(app.config, app.srcdir, app.doctreedir)
689689
assert len(updated) == 1
690690

691691

0 commit comments

Comments
 (0)