def __init__(self, dirname, filename, overrides, tags): self.overrides = overrides self.values = Config.config_values.copy() config = {} if "extensions" in overrides: # XXX do we need this? if isinstance(overrides["extensions"], string_types): config["extensions"] = overrides.pop("extensions").split(",") else: config["extensions"] = overrides.pop("extensions") if dirname is not None: config_file = path.join(dirname, filename) config["__file__"] = config_file config["tags"] = tags with cd(dirname): # we promise to have the config dir as current dir while the # config file is executed try: execfile_(filename, config) except SyntaxError as err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get("setup", None) self.extensions = config.get("extensions", [])
def __init__(self, dirname, filename, overrides, tags): self.overrides = overrides self.values = Config.config_values.copy() config = {} if dirname is not None: config_file = path.join(dirname, filename) config['__file__'] = config_file config['tags'] = tags with cd(dirname): # we promise to have the config dir as current dir while the # config file is executed try: execfile_(filename, config) except SyntaxError as err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) # override extensions after loading the configuration (otherwise it's pointless...) if 'extensions' in overrides: if isinstance(overrides['extensions'], string_types): config['extensions'] = overrides.pop('extensions').split(',') else: config['extensions'] = overrides.pop('extensions') self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get('setup', None) self.extensions = config.get('extensions', [])
def setup_command(request, tempdir, rootdir): """ Run `setup.py build_sphinx` with args and kwargs, pass it to the test and clean up properly. """ if hasattr(request.node, 'get_closest_marker'): # pytest-3.6.0 or newer marker = request.node.get_closest_marker('setup_command') else: marker = request.node.get_marker('setup_command') args = marker.args if marker else [] pkgrootdir = tempdir / 'test-setup' (rootdir / 'test-setup').copytree(pkgrootdir) with cd(pkgrootdir): pythonpath = os.path.dirname(os.path.dirname(sphinx.__file__)) if os.getenv('PYTHONPATH'): pythonpath = os.getenv('PYTHONPATH') + os.pathsep + pythonpath command = [sys.executable, 'setup.py', 'build_sphinx'] command.extend(args) proc = subprocess.Popen( command, env=dict(os.environ, PYTHONPATH=pythonpath), stdout=subprocess.PIPE, stderr=subprocess.PIPE) yield namedtuple('setup', 'pkgroot,proc')(pkgrootdir, proc)
def build_latexpdfja(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): os.system('%s all-pdf-ja' % self.makecmd) return 0
def eval_config_file(filename, tags): # type: (unicode, Tags) -> Dict[unicode, Any] """Evaluate a config file.""" namespace = {} # type: Dict[unicode, Any] namespace['__file__'] = filename namespace['tags'] = tags with cd(path.dirname(filename)): # during executing config file, current dir is changed to ``confdir``. try: execfile_(filename, namespace) except SyntaxError as err: msg = __("There is a syntax error in your configuration file: %s") if PY3: msg += __("\nDid you change the syntax from 2.x to 3.x?") raise ConfigError(msg % err) except SystemExit: msg = __("The configuration file (or one of the modules it imports) " "called sys.exit()") raise ConfigError(msg) except Exception: msg = __("There is a programmable error in your configuration file:\n\n%s") raise ConfigError(msg % traceback.format_exc()) return namespace
def build_info(self): # type: () -> int if self.run_generic_build('texinfo') > 0: return 1 with cd(self.builddir_join('texinfo')): os.system('%s info' % self.makecmd) return 0
def compile_math(latex, builder): # type: (unicode, Builder) -> unicode """Compile LaTeX macros for math to DVI.""" tempdir = ensure_tempdir(builder) filename = path.join(tempdir, 'math.tex') with codecs.open(filename, 'w', 'utf-8') as f: # type: ignore f.write(latex) # build latex command; old versions of latex don't have the # --output-directory option, so we have to manually chdir to the # temp dir to run it. command = [builder.config.imgmath_latex, '--interaction=nonstopmode'] # add custom args from the config file command.extend(builder.config.imgmath_latex_args) command.append('math.tex') with cd(tempdir): try: p = Popen(command, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise logger.warning(__('LaTeX command %r cannot be run (needed for math ' 'display), check the imgmath_latex setting'), builder.config.imgmath_latex) raise InvokeError stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('latex exited with error', stderr, stdout) return path.join(tempdir, 'math.dvi')
def build_latex_doc(app, status, warning, engine, docclass): app.config.latex_engine = engine app.config.latex_documents[0] = app.config.latex_documents[0][:4] + (docclass,) LaTeXTranslator.ignore_missing_images = True app.builder.build_all() # file from latex_additional_files assert (app.outdir / 'svgimg.svg').isfile() # now, try to run latex over it with cd(app.outdir): try: ensuredir(engine) p = Popen([engine, '--interaction=nonstopmode', '-output-directory=%s' % engine, 'SphinxTests.tex'], stdout=PIPE, stderr=PIPE) except OSError: # most likely the latex executable was not found raise SkipTest else: stdout, stderr = p.communicate() if p.returncode != 0: print(stdout) print(stderr) assert False, '%s exited with return code %s' % ( engine, p.returncode)
def build_latexpdfja(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 try: with cd(self.builddir_join('latex')): return subprocess.call([self.makecmd, 'all-pdf-ja']) except OSError: print('Error: Failed to run: %s' % self.makecmd) return 1
def build_info(self): # type: () -> int if self.run_generic_build('texinfo') > 0: return 1 try: with cd(self.builddir_join('texinfo')): return subprocess.call([self.makecmd, 'info']) except OSError: print('Error: Failed to run: %s' % self.makecmd) return 1
def get_master_doc(conf_file): '''returns the master_doc' variable stored in the given config file''' if not os.path.isfile(conf_file): raise ValueError("Not conf.py file: '%s'" % conf_file) # execute conf file to get the master document # Copied from sphinx.util.pycompat.py _globals = {"__file__": conf_file} # the namespace where toe xec stuff with six with cd(os.path.dirname(conf_file)): execfile_("conf.py", _globals) if 'master_doc' not in _globals: raise ValueError("'master_doc' undefined in '%s'" % conf_file) return _globals['master_doc']
def build_latexpdf(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 if sys.platform == 'win32': makecmd = os.environ.get('MAKE', 'make.bat') else: makecmd = self.makecmd try: with cd(self.builddir_join('latex')): return subprocess.call([makecmd, 'all-pdf']) except OSError: print('Error: Failed to run: %s' % makecmd) return 1
def compile_latex_document(app): # now, try to run latex over it with cd(app.outdir): try: ensuredir(app.config.latex_engine) p = Popen([app.config.latex_engine, '--interaction=nonstopmode', '-output-directory=%s' % app.config.latex_engine, 'SphinxTests.tex'], stdout=PIPE, stderr=PIPE) except OSError: # most likely the latex executable was not found raise SkipTest else: stdout, stderr = p.communicate() if p.returncode != 0: print(stdout) print(stderr) assert False, '%s exited with return code %s' % ( app.config.latex_engine, p.returncode)
def __init__(self, dirname, filename, overrides, tags): # type: (unicode, unicode, Dict, Tags) -> None self.overrides = overrides self.values = Config.config_values.copy() config = {} # type: Dict[unicode, Any] if dirname is not None: config_file = path.join(dirname, filename) config['__file__'] = config_file config['tags'] = tags with cd(dirname): # we promise to have the config dir as current dir while the # config file is executed try: execfile_(filename, config) except SyntaxError as err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) except Exception: raise ConfigError(CONFIG_ERROR % traceback.format_exc()) self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get('setup', None) # type: Callable if 'extensions' in overrides: if isinstance(overrides['extensions'], string_types): config['extensions'] = overrides.pop('extensions').split(',') else: config['extensions'] = overrides.pop('extensions') self.extensions = config.get('extensions', []) # type: List[unicode] # correct values of copyright year that are not coherent with # the SOURCE_DATE_EPOCH environment variable (if set) # See https://reproducible-builds.org/specs/source-date-epoch/ if getenv('SOURCE_DATE_EPOCH') is not None: for k in ('copyright', 'epub_copyright'): if k in config: config[k] = copyright_year_re.sub(r'\g<1>%s' % format_date('%Y'), config[k])
def setup_command(request, tempdir): """ Run `setup.py build_sphinx` with args and kwargs, pass it to the test and clean up properly. """ marker = request.node.get_marker('setup_command') args = marker.args if marker else [] pkgrootdir = tempdir / 'root' root.copytree(pkgrootdir) with cd(pkgrootdir): pythonpath = os.path.dirname(os.path.dirname(sphinx.__file__)) if os.getenv('PYTHONPATH'): pythonpath = os.getenv('PYTHONPATH') + os.pathsep + pythonpath command = [sys.executable, 'setup.py', 'build_sphinx'] command.extend(args) proc = subprocess.Popen(command, env=dict(os.environ, PYTHONPATH=pythonpath), stdout=subprocess.PIPE, stderr=subprocess.PIPE) yield namedtuple('setup', 'pkgroot,proc')(pkgrootdir, proc)
def __init__(self, dirname, filename, overrides, tags): self.overrides = overrides self.values = Config.config_values.copy() config = {} if 'extensions' in overrides: # XXX do we need this? if isinstance(overrides['extensions'], string_types): config['extensions'] = overrides.pop('extensions').split(',') else: config['extensions'] = overrides.pop('extensions') if dirname is not None: config_file = path.join(dirname, filename) config['__file__'] = config_file config['tags'] = tags with cd(dirname): # we promise to have the config dir as current dir while the # config file is executed try: execfile_(filename, config) except SyntaxError as err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get('setup', None) self.extensions = config.get('extensions', []) # correct values of copyright year that are not coherent with # the SOURCE_DATE_EPOCH environment variable (if set) # See https://reproducible-builds.org/specs/source-date-epoch/ if getenv('SOURCE_DATE_EPOCH') is not None: for k in ('copyright', 'epub_copyright'): if k in config: config[k] = copyright_year_re.sub( '\g<1>%s' % format_date('%Y'), config[k])
def test_msgfmt(app): app.builder.build_all() (app.outdir / 'en' / 'LC_MESSAGES').makedirs() with cd(app.outdir): try: p = Popen(['msginit', '--no-translator', '-i', 'markup.pot', '--locale', 'en_US'], stdout=PIPE, stderr=PIPE) except OSError: pytest.skip() # most likely msginit was not found else: stdout, stderr = p.communicate() if p.returncode != 0: print(stdout) print(stderr) assert False, 'msginit exited with return code %s' % \ p.returncode assert (app.outdir / 'en_US.po').isfile(), 'msginit failed' try: p = Popen(['msgfmt', 'en_US.po', '-o', os.path.join('en', 'LC_MESSAGES', 'test_root.mo')], stdout=PIPE, stderr=PIPE) except OSError: pytest.skip() # most likely msgfmt was not found else: stdout, stderr = p.communicate() if p.returncode != 0: print(stdout) print(stderr) assert False, 'msgfmt exited with return code %s' % \ p.returncode mo = app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo' assert mo.isfile(), 'msgfmt failed' _ = gettext.translation('test_root', app.outdir, languages=['en']).gettext assert _("Testing various markup") == u"Testing various markup"
def __init__(self, dirname, filename, overrides, tags): self.overrides = overrides self.values = Config.config_values.copy() config = {} if "extensions" in overrides: # XXX do we need this? if isinstance(overrides["extensions"], string_types): config["extensions"] = overrides.pop("extensions").split(",") else: config["extensions"] = overrides.pop("extensions") if dirname is not None: config_file = path.join(dirname, filename) config["__file__"] = config_file config["tags"] = tags with cd(dirname): # we promise to have the config dir as current dir while the # config file is executed try: execfile_(filename, config) except SyntaxError as err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get("setup", None) self.extensions = config.get("extensions", []) # correct values of copyright year that are not coherent with # the SOURCE_DATE_EPOCH environment variable (if set) # See https://reproducible-builds.org/specs/source-date-epoch/ if getenv("SOURCE_DATE_EPOCH") is not None: for k in ("copyright", "epub_copyright"): if k in config: config[k] = copyright_year_re.sub("\g<1>%s" % format_date("%Y"), config[k])
def eval_config_file(filename, tags): # type: (unicode, Tags) -> Dict[unicode, Any] """Evaluate a config file.""" namespace = {} # type: Dict[unicode, Any] namespace['__file__'] = filename namespace['tags'] = tags with cd(path.dirname(filename)): # during executing config file, current dir is changed to ``confdir``. try: execfile_(filename, namespace) except SyntaxError as err: msg = __("There is a syntax error in your configuration file: %s\n" "Did you change the syntax from 2.x to 3.x?") raise ConfigError(msg % err) except SystemExit: msg = __("The configuration file (or one of the modules it imports) " "called sys.exit()") raise ConfigError(msg) except Exception: msg = __("There is a programmable error in your configuration file:\n\n%s") raise ConfigError(msg % traceback.format_exc()) return namespace
def test_msgfmt(app): app.builder.build_all() (app.outdir / 'en' / 'LC_MESSAGES').makedirs() with cd(app.outdir): try: args = [ 'msginit', '--no-translator', '-i', 'markup.pot', '--locale', 'en_US' ] subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True) except OSError: pytest.skip() # most likely msginit was not found except CalledProcessError as exc: print(exc.stdout) print(exc.stderr) assert False, 'msginit exited with return code %s' % exc.returncode assert (app.outdir / 'en_US.po').isfile(), 'msginit failed' try: args = [ 'msgfmt', 'en_US.po', '-o', os.path.join('en', 'LC_MESSAGES', 'test_root.mo') ] subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True) except OSError: pytest.skip() # most likely msgfmt was not found except CalledProcessError as exc: print(exc.stdout) print(exc.stderr) assert False, 'msgfmt exited with return code %s' % exc.returncode mo = app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo' assert mo.isfile(), 'msgfmt failed' _ = gettext.translation('test_root', app.outdir, languages=['en']).gettext assert _("Testing various markup") == "Testing various markup"
def compile_latex_document(app): # now, try to run latex over it with cd(app.outdir): try: ensuredir(app.config.latex_engine) # keep a copy of latex file for this engine in case test fails copyfile('SphinxTests.tex', app.config.latex_engine + '/SphinxTests.tex') p = Popen([ app.config.latex_engine, '--interaction=nonstopmode', '-output-directory=%s' % app.config.latex_engine, 'SphinxTests.tex' ], stdout=PIPE, stderr=PIPE) except OSError: # most likely the latex executable was not found raise SkipTest else: stdout, stderr = p.communicate() if p.returncode != 0: print(stdout) print(stderr) assert False, '%s exited with return code %s' % ( app.config.latex_engine, p.returncode)
def build(path_book, path_output, config, toc, warningiserror, builder): """Convert your book's content to HTML or a PDF.""" # Paths for our notebooks PATH_BOOK = Path(path_book).absolute() if not PATH_BOOK.is_dir(): _error(f"Path to book isn't a directory: {PATH_BOOK}") # `book_config` is manual over-rides, `config` is the path to a _config.yml file book_config = {} # Choose sphinx builder builder_dict = { "html": "html", "linkcheck": "linkcheck", "pdfhtml": "singlehtml", "latex": "latex", "pdflatex": "latex", } if builder not in builder_dict.keys(): allowed_keys = tuple(builder_dict.keys()) _error( f"Value for --builder must be one of {allowed_keys}. Got '{builder}'" ) sphinx_builder = builder_dict[builder] # Table of contents if toc is None: if PATH_BOOK.joinpath("_toc.yml").exists(): toc = PATH_BOOK.joinpath("_toc.yml") else: _error("Couldn't find a Table of Contents file. To auto-generate " f"one, run\n\n\tjupyter-book toc {path_book}") book_config["globaltoc_path"] = str(toc) # Configuration file path_config = config if path_config is None: # Check if there's a `_config.yml` file in the source directory if PATH_BOOK.joinpath("_config.yml").exists(): path_config = str(PATH_BOOK.joinpath("_config.yml")) if path_config: if not Path(path_config).exists(): raise ValueError( f"Config file path given, but not found: {path_config}") # Builder-specific overrides if builder == "pdfhtml": book_config["html_theme_options"] = {"single_page": True} BUILD_PATH = path_output if path_output is not None else PATH_BOOK BUILD_PATH = Path(BUILD_PATH).joinpath("_build") if builder in ["html", "pdfhtml", "linkcheck"]: OUTPUT_PATH = BUILD_PATH.joinpath("html") elif builder in ["latex", "pdflatex"]: OUTPUT_PATH = BUILD_PATH.joinpath("latex") # Now call the Sphinx commands to build exc = build_sphinx( PATH_BOOK, OUTPUT_PATH, noconfig=True, path_config=path_config, confoverrides=book_config, builder=sphinx_builder, warningiserror=warningiserror, ) if exc: if builder == "linkcheck": _error( "The link checker either didn't finish or found broken links.\n" "See the report above.") else: _error("There was an error in building your book. " "Look above for the error message.") else: # Builder-specific options if builder == "html": path_output_rel = Path(op.relpath(OUTPUT_PATH, Path())) path_index = path_output_rel.joinpath("index.html") _message_box(f"""\ Finished generating HTML for book. Your book's HTML pages are here: {path_output_rel}{os.sep} You can look at your book by opening this file in a browser: {path_index} Or paste this line directly into your browser bar: file://{path_index.resolve()}\ """) if builder == "linkcheck": _message_box( "All links in your book are valid. See above for details.") if builder == "pdfhtml": print("Finished generating HTML for book...") print("Converting book HTML into PDF...") path_pdf_output = OUTPUT_PATH.parent.joinpath("pdf") path_pdf_output.mkdir(exist_ok=True) path_pdf_output = path_pdf_output.joinpath("book.pdf") html_to_pdf(OUTPUT_PATH.joinpath("index.html"), path_pdf_output) path_pdf_output_rel = Path(op.relpath(path_pdf_output, Path())) _message_box(f"""\ Finished generating PDF via HTML for book. Your PDF is here: {path_pdf_output_rel}\ """) if builder == "pdflatex": print("Finished generating latex for book...") print("Converting book latex into PDF...") # Convert to PDF via tex and template built Makefile and make.bat if sys.platform == "win32": makecmd = os.environ.get("MAKE", "make.bat") else: makecmd = os.environ.get("MAKE", "make") try: with cd(OUTPUT_PATH): output = subprocess.run([makecmd, "all-pdf"]) if output.returncode != 0: _error("Error: Failed to build pdf") return output.returncode _message_box(f"""\ A PDF of your book can be found at: {OUTPUT_PATH} """) except OSError: _error("Error: Failed to run: %s" % makecmd) return 1
def test_autogen(rootdir, tempdir): with cd(rootdir / 'test-templating'): args = ['-o', tempdir, '-t', '.', 'autosummary_templating.txt'] autogen_main(args) assert (tempdir / 'sphinx.application.TemplateBridge.rst').exists()
def build_info(self): # type: () -> int if self.run_generic_build('texinfo') > 0: return 1 with cd(self.builddir_join('texinfo')): return subprocess.call([self.makecmd, 'info'])
def build_info(self): if self.run_generic_build('texinfo') > 0: return 1 with cd(self.builddir_join('texinfo')): os.system('make info')
def build_latexpdf(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): return subprocess.call([self.makecmd, 'all-pdf'])
def build_latexpdf(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): os.system('make all-pdf')
from sphinx.builders.html import StandaloneHTMLBuilder _orig_setup = None # # import symbols from original conf file manually # import imp with open(conffile, 'r') as config_file: from sphinx.util.osutil import cd mod = imp.new_module("target_conf") mod.__file__ = conffile with cd(os.path.dirname(conffile)): exec(config_file, mod.__dict__) sys.modules['target_conf'] = mod G = globals() for (k,v) in mod.__dict__.items(): if k not in G: G[k] = v if k == "setup": G["_orig_setup"] = v class GollumBuilder(StandaloneHTMLBuilder): name = "gollum" theme = "gollum"
def main(argv=None): if argv is None: argv = sys.argv print("CGATReport: version %s started" % str("$Id$")) t = time.time() parser = optparse.OptionParser(version="%prog version: $Id$", usage=globals()["__doc__"]) parser.add_option("-j", "-a", "--num-jobs", dest="num_jobs", type="int", help="number of parallel jobs to run [default=%default]") parser.add_option("-v", "--verbose", dest="loglevel", type="int", help="loglevel. The higher, the more output " "[default=%default]") parser.set_defaults(num_jobs=2, loglevel=10,) parser.disable_interspersed_args() (options, args) = parser.parse_args() assert args[0].endswith( "sphinx-build"), "command line should contain sphinx-build" sphinx_parser = optparse.OptionParser( version="%prog version: $Id$", usage=globals()["__doc__"]) sphinx_parser.add_option("-b", type="string") sphinx_parser.add_option("-a") sphinx_parser.add_option("-E") sphinx_parser.add_option("-t", type="string") sphinx_parser.add_option("-d", type="string") sphinx_parser.add_option("-c", dest="confdir", type="string") sphinx_parser.add_option("-C") sphinx_parser.add_option("-D", type="string") sphinx_parser.add_option("-A", type="string") sphinx_parser.add_option("-n") sphinx_parser.add_option("-Q") sphinx_parser.add_option("-q") sphinx_parser.add_option("-w", type="string") sphinx_parser.add_option("-W") sphinx_parser.add_option("-P") sphinx_parser.add_option("-j", dest="num_jobs", type="int") sphinx_parser.set_defaults( confdir=None) (sphinx_options, sphinx_args) = sphinx_parser.parse_args(args[1:]) sourcedir = sphinx_args[0] # local conf.py overrides anything if os.path.exists("conf.py"): sphinx_options.confdir = "." elif sphinx_options.confdir is None: sphinx_options.confdir = sourcedir # import conf.py for source_suffix config_file = os.path.join(sphinx_options.confdir, "conf.py") if not os.path.exists(config_file): raise IOError("could not find {}".format(config_file)) config = {"__file__": config_file} with cd(sphinx_options.confdir): exec(compile(open(os.path.join(config_file)).read(), "conf.py", 'exec'), config) rst_files = getDirectives(options, args, sourcedir) cleanTrackers(rst_files, options, args) buildPlots(rst_files, options, args, sourcedir) buildDocument(options, args) print("CGATReport: finished in %i seconds" % (time.time() - t)) debug("build.py: profile: finished: %i seconds" % (time.time() - t))
def build_latexpdfja(self): if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): os.system('make all-pdf-ja')
def build_xelatexpdf(self): if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): os.system('make PDFLATEX=xelatex all-pdf')
def build_latexpdf(self): if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): os.system('%s all-pdf' % self.makecmd)
def build(path_book, path_output, config, toc, warningiserror, builder): """Convert your book's content to HTML or a PDF.""" # Paths for our notebooks PATH_BOOK = Path(path_book).absolute() if not PATH_BOOK.is_dir(): _error(f"Path to book isn't a directory: {PATH_BOOK}") book_config = {} builder_dict = { "html": "html", "linkcheck": "linkcheck", "pdfhtml": "singlehtml", "latex": "latex", "pdflatex": "latex", } if builder not in builder_dict.keys(): allowed_keys = tuple(builder_dict.keys()) _error( f"Value for --builder must be one of {allowed_keys}. Got '{builder}'" ) sphinx_builder = builder_dict[builder] # Table of contents if toc is None: if PATH_BOOK.joinpath("_toc.yml").exists(): toc = PATH_BOOK.joinpath("_toc.yml") else: _error("Couldn't find a Table of Contents file. To auto-generate " f"one, run\n\n\tjupyter-book toc {path_book}") book_config["globaltoc_path"] = str(toc) # Configuration file if config is None: if PATH_BOOK.joinpath("_config.yml").exists(): config = PATH_BOOK.joinpath("_config.yml") extra_extensions = None if config is not None: book_config["yaml_config_path"] = str(config) config_yaml = yaml.safe_load(config.read_text()) # Pop the extra extensions since we need to append, not replace extra_extensions = config_yaml.pop("sphinx", {}).get("extra_extensions") # Support Top Level config Passthrough # https://www.sphinx-doc.org/en/latest/usage/configuration.html#project-information sphinx_options = ["project", "author", "copyright"] for option in sphinx_options: if option in config_yaml.keys(): book_config[option] = config_yaml[option] # Builder-specific overrides latex_config = None if builder == "pdfhtml": book_config["html_theme_options"] = {"single_page": True} if builder == "pdflatex": if "latex" in config_yaml.keys(): latex_config = config_yaml.pop("latex") if "title" in config_yaml.keys(): # Note: a latex_documents specified title takes precendence # over a top level title if (latex_config is not None and "title" not in latex_config["latex_documents"].keys()): latex_config["latex_documents"]["title"] = config_yaml["title"] else: latex_config = { "latex_documents": { "title": config_yaml["title"] } } BUILD_PATH = path_output if path_output is not None else PATH_BOOK BUILD_PATH = Path(BUILD_PATH).joinpath("_build") if builder in ["html", "pdfhtml", "linkcheck"]: OUTPUT_PATH = BUILD_PATH.joinpath("html") elif builder in ["latex", "pdflatex"]: OUTPUT_PATH = BUILD_PATH.joinpath("latex") # Now call the Sphinx commands to build exc = build_sphinx( PATH_BOOK, OUTPUT_PATH, noconfig=True, confoverrides=book_config, latexoverrides=latex_config, builder=sphinx_builder, warningiserror=warningiserror, extra_extensions=extra_extensions, ) if exc: if builder == "linkcheck": _error( "The link checker either didn't finish or found broken links.\n" "See the report above.") else: _error("There was an error in building your book. " "Look above for the error message.") else: # Builder-specific options if builder == "html": path_output_rel = Path(op.relpath(OUTPUT_PATH, Path())) path_index = path_output_rel.joinpath("index.html") _message_box(f"""\ Finished generating HTML for book. Your book's HTML pages are here: {path_output_rel}{os.sep} You can look at your book by opening this file in a browser: {path_index} Or paste this line directly into your browser bar: file://{path_index.resolve()}\ """) if builder == "linkcheck": _message_box( "All links in your book are valid. See above for details.") if builder == "pdfhtml": print("Finished generating HTML for book...") print("Converting book HTML into PDF...") path_pdf_output = OUTPUT_PATH.parent.joinpath("pdf") path_pdf_output.mkdir(exist_ok=True) path_pdf_output = path_pdf_output.joinpath("book.pdf") html_to_pdf(OUTPUT_PATH.joinpath("index.html"), path_pdf_output) path_pdf_output_rel = Path(op.relpath(path_pdf_output, Path())) _message_box(f"""\ Finished generating PDF via HTML for book. Your PDF is here: {path_pdf_output_rel}\ """) if builder == "pdflatex": print("Finished generating latex for book...") print("Converting book latex into PDF...") # Convert to PDF via tex and template built Makefile and make.bat if sys.platform == "win32": makecmd = os.environ.get("MAKE", "make.bat") else: makecmd = os.environ.get("MAKE", "make") try: with cd(OUTPUT_PATH): output = subprocess.run([makecmd, "all-pdf"]) if output.returncode != 0: _error("Error: Failed to build pdf") return output.returncode _message_box(f"""\ A PDF of your book can be found at: {OUTPUT_PATH} """) except OSError: _error("Error: Failed to run: %s" % makecmd) return 1
def render_math(self, math): """Render the LaTeX math expression *math* using latex and dvipng or dvisvgm. Return the filename relative to the built document and the "depth", that is, the distance of image bottom and baseline in pixels, if the option to use preview_latex is switched on. Error handling may seem strange, but follows a pattern: if LaTeX or dvipng (dvisvgm) aren't available, only a warning is generated (since that enables people on machines without these programs to at least build the rest of the docs successfully). If the programs are there, however, they may not fail since that indicates a problem in the math source. """ image_format = self.builder.config.imgmath_image_format if image_format not in ("png", "svg"): raise MathExtError('imgmath_image_format must be either "png" or "svg"') font_size = self.builder.config.imgmath_font_size use_preview = self.builder.config.imgmath_use_preview latex = DOC_HEAD + self.builder.config.imgmath_latex_preamble latex += (use_preview and DOC_BODY_PREVIEW or DOC_BODY) % (font_size, int(round(font_size * 1.2)), math) shasum = "%s.%s" % (sha1(latex.encode("utf-8")).hexdigest(), image_format) relfn = posixpath.join(self.builder.imgpath, "math", shasum) outfn = path.join(self.builder.outdir, self.builder.imagedir, "math", shasum) if path.isfile(outfn): depth = read_png_depth(outfn) return relfn, depth # if latex or dvipng (dvisvgm) has failed once, don't bother to try again if hasattr(self.builder, "_imgmath_warned_latex") or hasattr(self.builder, "_imgmath_warned_image_translator"): return None, None # use only one tempdir per build -- the use of a directory is cleaner # than using temporary files, since we can clean up everything at once # just removing the whole directory (see cleanup_tempdir) if not hasattr(self.builder, "_imgmath_tempdir"): tempdir = self.builder._imgmath_tempdir = tempfile.mkdtemp() else: tempdir = self.builder._imgmath_tempdir tf = codecs.open(path.join(tempdir, "math.tex"), "w", "utf-8") tf.write(latex) tf.close() # build latex command; old versions of latex don't have the # --output-directory option, so we have to manually chdir to the # temp dir to run it. ltx_args = [self.builder.config.imgmath_latex, "--interaction=nonstopmode"] # add custom args from the config file ltx_args.extend(self.builder.config.imgmath_latex_args) ltx_args.append("math.tex") with cd(tempdir): try: p = Popen(ltx_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise self.builder.warn( "LaTeX command %r cannot be run (needed for math " "display), check the imgmath_latex setting" % self.builder.config.imgmath_latex ) self.builder._imgmath_warned_latex = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError("latex exited with error", stderr, stdout) ensuredir(path.dirname(outfn)) if image_format == "png": image_translator = "dvipng" image_translator_executable = self.builder.config.imgmath_dvipng # use some standard dvipng arguments image_translator_args = [self.builder.config.imgmath_dvipng] image_translator_args += ["-o", outfn, "-T", "tight", "-z9"] # add custom ones from config value image_translator_args.extend(self.builder.config.imgmath_dvipng_args) if use_preview: image_translator_args.append("--depth") elif image_format == "svg": image_translator = "dvisvgm" image_translator_executable = self.builder.config.imgmath_dvisvgm # use some standard dvisvgm arguments image_translator_args = [self.builder.config.imgmath_dvisvgm] image_translator_args += ["-o", outfn] # add custom ones from config value image_translator_args.extend(self.builder.config.imgmath_dvisvgm_args) # last, the input file name image_translator_args.append(path.join(tempdir, "math.dvi")) else: raise MathExtError('imgmath_image_format must be either "png" or "svg"') # last, the input file name image_translator_args.append(path.join(tempdir, "math.dvi")) try: p = Popen(image_translator_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise self.builder.warn( "%s command %r cannot be run (needed for math " "display), check the imgmath_%s setting" % image_translator, image_translator_executable, image_translator, ) self.builder._imgmath_warned_image_translator = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError("%s exited with error", image_translator, stderr, stdout) depth = None if use_preview and image_format == "png": # depth is only useful for png for line in stdout.splitlines(): m = depth_re.match(line) if m: depth = int(m.group(1)) write_png_depth(outfn, depth) break return relfn, depth
def build_latexpdfja(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): os.system('%s all-pdf-ja' % self.makecmd)
def build(path_book, path_output, config, toc, warningiserror, builder): """Convert your book's content to HTML or a PDF.""" # Paths for our notebooks PATH_BOOK = Path(path_book).absolute() # `book_config` is manual over-rides, `config` is the path to a _config.yml file book_config = {} # Table of contents # TODO Set TOC dynamically to default value and let Click handle this check if toc is None: toc = PATH_BOOK.joinpath("_toc.yml") else: toc = Path(toc) if not toc.exists(): _error( "Couldn't find a Table of Contents file. To auto-generate " f"one, run\n\n\tjupyter-book toc {path_book}" ) book_config["globaltoc_path"] = str(toc) # Configuration file path_config = config if path_config is None: # Check if there's a `_config.yml` file in the source directory if PATH_BOOK.joinpath("_config.yml").exists(): path_config = str(PATH_BOOK.joinpath("_config.yml")) if path_config: if not Path(path_config).exists(): raise ValueError(f"Config file path given, but not found: {path_config}") # Builder-specific overrides if builder == "pdfhtml": book_config["html_theme_options"] = {"single_page": True} # TODO Use click to set value of path_output dynamically based on path_book BUILD_PATH = path_output if path_output is not None else PATH_BOOK BUILD_PATH = Path(BUILD_PATH).joinpath("_build") if builder in ["html", "pdfhtml", "linkcheck"]: OUTPUT_PATH = BUILD_PATH.joinpath("html") elif builder in ["latex", "pdflatex"]: OUTPUT_PATH = BUILD_PATH.joinpath("latex") # Check whether the table of contents has changed. If so we rebuild all freshenv = False if toc and BUILD_PATH.joinpath(".doctrees").exists(): toc_modified = toc.stat().st_mtime build_files = BUILD_PATH.rglob(".doctrees/*") build_modified = max([os.stat(ii).st_mtime for ii in build_files]) # If the toc file has been modified after the build we need to force rebuild freshenv = toc_modified > build_modified # Now call the Sphinx commands to build exc = build_sphinx( PATH_BOOK, OUTPUT_PATH, noconfig=True, path_config=path_config, confoverrides=book_config, builder=BUILDER_OPTS[builder], warningiserror=warningiserror, freshenv=freshenv, ) if exc: if builder == "linkcheck": _error( "The link checker either didn't finish or found broken links.\n" "See the report above." ) else: _error( "There was an error in building your book. " "Look above for the error message." ) else: # Builder-specific options if builder == "html": path_output_rel = Path(op.relpath(OUTPUT_PATH, Path())) path_index = path_output_rel.joinpath("index.html") _message_box( f"""\ Finished generating HTML for book. Your book's HTML pages are here: {path_output_rel}{os.sep} You can look at your book by opening this file in a browser: {path_index} Or paste this line directly into your browser bar: file://{path_index.resolve()}\ """ ) if builder == "linkcheck": _message_box("All links in your book are valid. See above for details.") if builder == "pdfhtml": print("Finished generating HTML for book...") print("Converting book HTML into PDF...") path_pdf_output = OUTPUT_PATH.parent.joinpath("pdf") path_pdf_output.mkdir(exist_ok=True) path_pdf_output = path_pdf_output.joinpath("book.pdf") html_to_pdf(OUTPUT_PATH.joinpath("index.html"), path_pdf_output) path_pdf_output_rel = Path(op.relpath(path_pdf_output, Path())) _message_box( f"""\ Finished generating PDF via HTML for book. Your PDF is here: {path_pdf_output_rel}\ """ ) if builder == "pdflatex": print("Finished generating latex for book...") print("Converting book latex into PDF...") # Convert to PDF via tex and template built Makefile and make.bat if sys.platform == "win32": makecmd = os.environ.get("MAKE", "make.bat") else: makecmd = os.environ.get("MAKE", "make") try: with cd(OUTPUT_PATH): output = subprocess.run([makecmd, "all-pdf"]) if output.returncode != 0: _error("Error: Failed to build pdf") return output.returncode _message_box( f"""\ A PDF of your book can be found at: {OUTPUT_PATH} """ ) except OSError: _error("Error: Failed to run: %s" % makecmd) return 1
def build_info(self): if self.run_generic_build("texinfo") > 0: return 1 with cd(self.builddir_join("texinfo")): os.system("make info")
def build_latexpdfja(self): if self.run_generic_build("latex") > 0: return 1 with cd(self.builddir_join("latex")): os.system("make all-pdf-ja")
def setup_class(cls): """Run Sphinx against the dir adjacent to the testcase.""" cls.docs_dir = join(cls.this_dir(), 'source', 'docs') with cd(cls.docs_dir): if sphinx_main(['.', '-b', 'text', '-E', '_build']): raise RuntimeError('Sphinx build exploded.')
def build_latexpdfja(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): return subprocess.call([self.makecmd, 'all-pdf-ja'])
def setup_class(cls): cls.docs_dir = join(dirname(__file__), 'source', 'docs') with cd(cls.docs_dir): sphinx_main(['dummy', '-b', 'text', '-E', '.', '_build'])
def render_math(self, math): """Render the LaTeX math expression *math* using latex and dvipng. Return the filename relative to the built document and the "depth", that is, the distance of image bottom and baseline in pixels, if the option to use preview_latex is switched on. Error handling may seem strange, but follows a pattern: if LaTeX or dvipng aren't available, only a warning is generated (since that enables people on machines without these programs to at least build the rest of the docs successfully). If the programs are there, however, they may not fail since that indicates a problem in the math source. """ use_preview = self.builder.config.pngmath_use_preview latex = DOC_HEAD + self.builder.config.pngmath_latex_preamble latex += (use_preview and DOC_BODY_PREVIEW or DOC_BODY) % math shasum = "%s.png" % sha1(latex.encode('utf-8')).hexdigest() relfn = posixpath.join(self.builder.imgpath, 'math', shasum) outfn = path.join(self.builder.outdir, self.builder.imagedir, 'math', shasum) if path.isfile(outfn): depth = read_png_depth(outfn) return relfn, depth # if latex or dvipng has failed once, don't bother to try again if hasattr(self.builder, '_mathpng_warned_latex') or \ hasattr(self.builder, '_mathpng_warned_dvipng'): return None, None # use only one tempdir per build -- the use of a directory is cleaner # than using temporary files, since we can clean up everything at once # just removing the whole directory (see cleanup_tempdir) if not hasattr(self.builder, '_mathpng_tempdir'): tempdir = self.builder._mathpng_tempdir = tempfile.mkdtemp() else: tempdir = self.builder._mathpng_tempdir tf = codecs.open(path.join(tempdir, 'math.tex'), 'w', 'utf-8') tf.write(latex) tf.close() # build latex command; old versions of latex don't have the # --output-directory option, so we have to manually chdir to the # temp dir to run it. ltx_args = [self.builder.config.pngmath_latex, '--interaction=nonstopmode'] # add custom args from the config file ltx_args.extend(self.builder.config.pngmath_latex_args) ltx_args.append('math.tex') with cd(tempdir): try: p = Popen(ltx_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise self.builder.warn('LaTeX command %r cannot be run (needed for math ' 'display), check the pngmath_latex setting' % self.builder.config.pngmath_latex) self.builder._mathpng_warned_latex = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('latex exited with error', stderr, stdout) ensuredir(path.dirname(outfn)) # use some standard dvipng arguments dvipng_args = [self.builder.config.pngmath_dvipng] dvipng_args += ['-o', outfn, '-T', 'tight', '-z9'] # add custom ones from config value dvipng_args.extend(self.builder.config.pngmath_dvipng_args) if use_preview: dvipng_args.append('--depth') # last, the input file name dvipng_args.append(path.join(tempdir, 'math.dvi')) try: p = Popen(dvipng_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise self.builder.warn('dvipng command %r cannot be run (needed for math ' 'display), check the pngmath_dvipng setting' % self.builder.config.pngmath_dvipng) self.builder._mathpng_warned_dvipng = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('dvipng exited with error', stderr, stdout) depth = None if use_preview: for line in stdout.splitlines(): m = depth_re.match(line) if m: depth = int(m.group(1)) write_png_depth(outfn, depth) break return relfn, depth
GAME_DIR = os.environ.get("EVGAMEDIR") if not (EV_ROOT and GAME_DIR): err = ( "The EVDIR and EVGAMEDIR environment variables must be set to " "the absolute paths to the evennia/ repo and an initialized " "evennia gamedir respectively." ) raise RuntimeError(err) print("Evennia root: {}, Game dir: {}".format(EV_ROOT, GAME_DIR)) sys.path.insert(1, EV_ROOT) sys.path.insert(1, GAME_DIR) with cd(GAME_DIR): # set up Evennia so its sources can be parsed os.environ["DJANGO_SETTINGS_MODULE"] = "server.conf.settings" import django # noqa django.setup() import evennia # noqa evennia._init() from evennia.utils.ansi import strip_raw_ansi as ansi_clean if _no_autodoc:
def render_math(self, math): """Render the LaTeX math expression *math* using latex and dvipng or dvisvgm. Return the filename relative to the built document and the "depth", that is, the distance of image bottom and baseline in pixels, if the option to use preview_latex is switched on. Error handling may seem strange, but follows a pattern: if LaTeX or dvipng (dvisvgm) aren't available, only a warning is generated (since that enables people on machines without these programs to at least build the rest of the docs successfully). If the programs are there, however, they may not fail since that indicates a problem in the math source. """ image_format = self.builder.config.imgmath_image_format if image_format not in ('png', 'svg'): raise MathExtError( 'imgmath_image_format must be either "png" or "svg"') font_size = self.builder.config.imgmath_font_size use_preview = self.builder.config.imgmath_use_preview latex = DOC_HEAD + self.builder.config.imgmath_latex_preamble latex += (use_preview and DOC_BODY_PREVIEW or DOC_BODY) % (font_size, int(round(font_size * 1.2)), math) shasum = "%s.%s" % (sha1(latex.encode('utf-8')).hexdigest(), image_format) relfn = posixpath.join(self.builder.imgpath, 'math', shasum) outfn = path.join(self.builder.outdir, self.builder.imagedir, 'math', shasum) if path.isfile(outfn): depth = read_png_depth(outfn) return relfn, depth # if latex or dvipng (dvisvgm) has failed once, don't bother to try again if hasattr(self.builder, '_imgmath_warned_latex') or \ hasattr(self.builder, '_imgmath_warned_image_translator'): return None, None # use only one tempdir per build -- the use of a directory is cleaner # than using temporary files, since we can clean up everything at once # just removing the whole directory (see cleanup_tempdir) if not hasattr(self.builder, '_imgmath_tempdir'): tempdir = self.builder._imgmath_tempdir = tempfile.mkdtemp() else: tempdir = self.builder._imgmath_tempdir tf = codecs.open(path.join(tempdir, 'math.tex'), 'w', 'utf-8') tf.write(latex) tf.close() # build latex command; old versions of latex don't have the # --output-directory option, so we have to manually chdir to the # temp dir to run it. ltx_args = [self.builder.config.imgmath_latex, '--interaction=nonstopmode'] # add custom args from the config file ltx_args.extend(self.builder.config.imgmath_latex_args) ltx_args.append('math.tex') with cd(tempdir): try: p = Popen(ltx_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise self.builder.warn( 'LaTeX command %r cannot be run (needed for math ' 'display), check the imgmath_latex setting' % self.builder.config.imgmath_latex) self.builder._imgmath_warned_latex = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('latex exited with error', stderr, stdout) ensuredir(path.dirname(outfn)) if image_format == 'png': image_translator = 'dvipng' image_translator_executable = self.builder.config.imgmath_dvipng # use some standard dvipng arguments image_translator_args = [self.builder.config.imgmath_dvipng] image_translator_args += ['-o', outfn, '-T', 'tight', '-z9'] # add custom ones from config value image_translator_args.extend(self.builder.config.imgmath_dvipng_args) if use_preview: image_translator_args.append('--depth') elif image_format == 'svg': image_translator = 'dvisvgm' image_translator_executable = self.builder.config.imgmath_dvisvgm # use some standard dvisvgm arguments image_translator_args = [self.builder.config.imgmath_dvisvgm] image_translator_args += ['-o', outfn] # add custom ones from config value image_translator_args.extend(self.builder.config.imgmath_dvisvgm_args) else: raise MathExtError( 'imgmath_image_format must be either "png" or "svg"') # last, the input file name image_translator_args.append(path.join(tempdir, 'math.dvi')) try: p = Popen(image_translator_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise self.builder.warn( '%s command %r cannot be run (needed for math ' 'display), check the imgmath_%s setting' % (image_translator, image_translator_executable, image_translator)) self.builder._imgmath_warned_image_translator = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('%s exited with error' % image_translator, stderr, stdout) depth = None if use_preview and image_format == 'png': # depth is only useful for png for line in stdout.splitlines(): m = depth_re.match(line) if m: depth = int(m.group(1)) write_png_depth(outfn, depth) break return relfn, depth
def builder_specific_actions(exc, builder, output_path, cmd_type, page_name=None): if exc: _error(f"There was an error in building your {cmd_type}. " "Look above for the error message.") else: # Builder-specific options if builder == "html": path_output_rel = Path(op.relpath(output_path, Path())) if cmd_type == "page": path_page = path_output_rel.joinpath(f"{page_name}.html") # Write an index file if it doesn't exist so we get redirects path_index = path_output_rel.joinpath("index.html") if not path_index.exists(): path_index.write_text( REDIRECT_TEXT.format(first_page=path_page.name)) _message_box( dedent(f""" Page build finished. Your page folder is: {path_page.parent}{os.sep} Open your page at: {path_page} """)) elif cmd_type == "book": path_output_rel = Path(op.relpath(output_path, Path())) path_index = path_output_rel.joinpath("index.html") _message_box(f"""\ Finished generating HTML for {cmd_type}. Your book's HTML pages are here: {path_output_rel}{os.sep} You can look at your book by opening this file in a browser: {path_index} Or paste this line directly into your browser bar: file://{path_index.resolve()}\ """) if builder == "pdfhtml": print(f"Finished generating HTML for {cmd_type}...") print(f"Converting {cmd_type} HTML into PDF...") path_pdf_output = output_path.parent.joinpath("pdf") path_pdf_output.mkdir(exist_ok=True) if cmd_type == "book": path_pdf_output = path_pdf_output.joinpath("book.pdf") html_to_pdf(output_path.joinpath("index.html"), path_pdf_output) elif cmd_type == "page": path_pdf_output = path_pdf_output.joinpath(page_name + ".pdf") html_to_pdf(output_path.joinpath(page_name + ".html"), path_pdf_output) path_pdf_output_rel = Path(op.relpath(path_pdf_output, Path())) _message_box(f"""\ Finished generating PDF via HTML for {cmd_type}. Your PDF is here: {path_pdf_output_rel}\ """) if builder == "pdflatex": print(f"Finished generating latex for {cmd_type}...") print(f"Converting {cmd_type} latex into PDF...") # Convert to PDF via tex and template built Makefile and make.bat if sys.platform == "win32": makecmd = os.environ.get("MAKE", "make.bat") else: makecmd = os.environ.get("MAKE", "make") try: with cd(output_path): output = subprocess.run([makecmd, "all-pdf"]) if output.returncode != 0: _error("Error: Failed to build pdf") return output.returncode _message_box(f"""\ A PDF of your {cmd_type} can be found at: {output_path} """) except OSError: _error("Error: Failed to run: %s" % makecmd) return 1
def setup_class(cls): cls.docs_dir = join(dirname(__file__), 'source', 'docs') with cd(cls.docs_dir): if sphinx_main(['dummy', '-b', 'text', '-E', '.', '_build']): raise RuntimeError('Sphinx build exploded.')
def handle(self): output_directory = Path(self.args.output_directory) # We simulate pybabel and sphinx-build commands. Variable names are chosen to match upstream code. # For sphinx-build, the code path is: # # * bin/sphinx-build calls main() in sphinx, which calls build_main(), which calls main() in sphinx.cmdline # * main() calls Sphinx(…).build(…) in sphinx.application # sphinx-build -E -q … kwargs = { 'confoverrides': { 'source_suffix': ['.rst', '.md'], 'source_parsers': { '.md': CommonMarkParser, }, }, 'freshenv': True, 'parallel': 1, } if not self.args.verbose: kwargs.update(status=None) # For pybabel, the code path is: # # * bin/pybabel calls main() in babel.messages.frontend # * main() calls CommandLineInterface().run(sys.argv) # * CommandLineInterface() calls extract_messages(), which: # 1. Reads the input path and method map from command-line options # 2. Instantiates a catalog # 3. Calls extract_from_dir() in babel.messages.extract to extract messages # 4. extract_from_dir() calls check_and_call_extract_file() to find the method in the method map # 5. check_and_call_extract_file() calls extract_from_file() to open a file for extraction # 6. extract_from_file() calls extract() to extract messages # 7. Adds the messages to the catalog # 8. Writes a POT file # 1. Reads the input path and method map from command-line options arguments = [ # pybabel extract -F babel_ocds_codelist.cfg . -o $(POT_DIR)/$(DOMAIN_PREFIX)codelists.pot ('codelists.pot', [ ('codelists/*.csv', extract_codelist), ]), # pybabel extract -F babel_ocds_schema.cfg . -o $(POT_DIR)/$(DOMAIN_PREFIX)schema.pot ('schema.pot', [ ('*-schema.json', extract_schema), ('extension.json', extract_extension_metadata), ]), ] for version in self.versions(): if not version.download_url: logger.warning('No Download URL for {}=={}'.format( version.id, version.version)) outdir = output_directory / version.id / version.version outdir.mkdir(parents=True, exist_ok=True) # See the `files` method of `ExtensionVersion` for similar code. response = requests.get(version.download_url, allow_redirects=True) response.raise_for_status() with closing(ZipFile(BytesIO(response.content))) as zipfile: names = zipfile.namelist() start = len(names[0]) for output_file, method_map in arguments: # 2. Instantiates a catalog catalog = Catalog() # 3. Calls extract_from_dir() in babel.messages.extract to extract messages for name in names[1:]: filename = name[start:] # 4. extract_from_dir() calls check_and_call_extract_file() for pattern, method in method_map: if not pathmatch(pattern, filename): continue # 5. check_and_call_extract_file() calls extract_from_file() with zipfile.open(name) as fileobj: # 6. extract_from_file() calls extract() to extract messages for lineno, message, comments, context in extract( method, fileobj): # 7. Adds the messages to the catalog catalog.add(message, None, [(filename, lineno)], auto_comments=comments, context=context) break # 8. Writes a POT file if catalog: with open(outdir / output_file, 'wb') as outfile: write_po(outfile, catalog) with TemporaryDirectory() as srcdir: for info in zipfile.infolist()[1:]: filename = info.filename[start:] if filename[-1] != '/' and filename.startswith( 'docs/') or filename == 'README.md': info.filename = filename zipfile.extract(info, srcdir) with cd(srcdir): # Eliminates a warning, without change to output. with open('contents.rst', 'w') as f: f.write( '.. toctree::\n :glob:\n\n docs/*\n README' ) # sphinx-build -b gettext $(DOCS_DIR) $(POT_DIR) app = Sphinx('.', None, '.', '.', 'gettext', **kwargs) app.build(True) # https://stackoverflow.com/questions/15408348 content = subprocess.run(['msgcat', *glob('*.pot')], check=True, stdout=subprocess.PIPE).stdout with open(outdir / 'docs.pot', 'wb') as f: f.write(content)
# -- API/Autodoc --------------------------------------------------------------- # automatic creation of API documentation. This requires a valid Evennia setup _no_autodoc = os.environ.get("NOAUTODOC") ansi_clean = None if not _no_autodoc: # we must set up Evennia and its paths for autodocs to work EV_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(1, EV_ROOT) with cd(EV_ROOT): # set up Evennia so its sources can be parsed os.environ["DJANGO_SETTINGS_MODULE"] = "evennia.settings_default" import django # noqa django.setup() import evennia # noqa evennia._init() from evennia.utils.ansi import strip_raw_ansi as ansi_clean if _no_autodoc: exclude_patterns = ["api/*"]
def build_info(self): # type: () -> int if self.run_generic_build('texinfo') > 0: return 1 with cd(self.builddir_join('texinfo')): os.system('%s info' % self.makecmd)
def render_math(self, math): # type: (nodes.NodeVisitor, unicode) -> Tuple[unicode, int] """Render the LaTeX math expression *math* using latex and dvipng. Return the filename relative to the built document and the "depth", that is, the distance of image bottom and baseline in pixels, if the option to use preview_latex is switched on. Error handling may seem strange, but follows a pattern: if LaTeX or dvipng aren't available, only a warning is generated (since that enables people on machines without these programs to at least build the rest of the docs successfully). If the programs are there, however, they may not fail since that indicates a problem in the math source. """ use_preview = self.builder.config.pngmath_use_preview latex = DOC_HEAD + self.builder.config.pngmath_latex_preamble latex += (use_preview and DOC_BODY_PREVIEW or DOC_BODY) % math shasum = "%s.png" % sha1(latex.encode('utf-8')).hexdigest() relfn = posixpath.join(self.builder.imgpath, 'math', shasum) outfn = path.join(self.builder.outdir, self.builder.imagedir, 'math', shasum) if path.isfile(outfn): depth = read_png_depth(outfn) return relfn, depth # if latex or dvipng has failed once, don't bother to try again if hasattr(self.builder, '_mathpng_warned_latex') or \ hasattr(self.builder, '_mathpng_warned_dvipng'): return None, None # use only one tempdir per build -- the use of a directory is cleaner # than using temporary files, since we can clean up everything at once # just removing the whole directory (see cleanup_tempdir) if not hasattr(self.builder, '_mathpng_tempdir'): tempdir = self.builder._mathpng_tempdir = tempfile.mkdtemp() else: tempdir = self.builder._mathpng_tempdir with codecs.open(path.join(tempdir, 'math.tex'), 'w', 'utf-8') as tf: # type: ignore tf.write(latex) # build latex command; old versions of latex don't have the # --output-directory option, so we have to manually chdir to the # temp dir to run it. ltx_args = [self.builder.config.pngmath_latex, '--interaction=nonstopmode'] # add custom args from the config file ltx_args.extend(self.builder.config.pngmath_latex_args) ltx_args.append('math.tex') with cd(tempdir): try: p = Popen(ltx_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise logger.warning( 'LaTeX command %r cannot be run (needed for math ' 'display), check the pngmath_latex setting', self.builder.config.pngmath_latex) self.builder._mathpng_warned_latex = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('latex exited with error', stderr, stdout) ensuredir(path.dirname(outfn)) # use some standard dvipng arguments dvipng_args = [self.builder.config.pngmath_dvipng] dvipng_args += ['-o', outfn, '-T', 'tight', '-z9'] # add custom ones from config value dvipng_args.extend(self.builder.config.pngmath_dvipng_args) if use_preview: dvipng_args.append('--depth') # last, the input file name dvipng_args.append(path.join(tempdir, 'math.dvi')) try: p = Popen(dvipng_args, stdout=PIPE, stderr=PIPE) except OSError as err: if err.errno != ENOENT: # No such file or directory raise logger.warning( 'dvipng command %r cannot be run (needed for math ' 'display), check the pngmath_dvipng setting', self.builder.config.pngmath_dvipng) self.builder._mathpng_warned_dvipng = True return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('dvipng exited with error', stderr, stdout) depth = None if use_preview: for line in stdout.splitlines(): m = depth_re.match(line) if m: depth = int(m.group(1)) write_png_depth(outfn, depth) break return relfn, depth
def builder_specific_actions(result, builder, output_path, cmd_type, page_name=None, print_func=print): """Run post-sphinx-build actions. :param result: the result of the build execution; a status code or and exception """ from sphinx.util.osutil import cd from ..pdf import html_to_pdf from ..sphinx import REDIRECT_TEXT if isinstance(result, Exception): msg = (f"There was an error in building your {cmd_type}. " "Look above for the cause.") # TODO ideally we probably only want the original traceback here raise RuntimeError(_message_box(msg, color="red", doprint=False)) from result elif result: msg = ( f"Building your {cmd_type}, returns a non-zero exit code ({result}). " "Look above for the cause.") _message_box(msg, color="red", print_func=click.echo) sys.exit(result) # Builder-specific options if builder == "html": path_output_rel = Path(op.relpath(output_path, Path())) if cmd_type == "page": path_page = path_output_rel.joinpath(f"{page_name}.html") # Write an index file if it doesn't exist so we get redirects path_index = path_output_rel.joinpath("index.html") if not path_index.exists(): path_index.write_text( REDIRECT_TEXT.format(first_page=path_page.name)) _message_box( dedent(f""" Page build finished. Your page folder is: {path_page.parent}{os.sep} Open your page at: {path_page} """)) elif cmd_type == "book": path_output_rel = Path(op.relpath(output_path, Path())) path_index = path_output_rel.joinpath("index.html") _message_box(f"""\ Finished generating HTML for {cmd_type}. Your book's HTML pages are here: {path_output_rel}{os.sep} You can look at your book by opening this file in a browser: {path_index} Or paste this line directly into your browser bar: file://{path_index.resolve()}\ """) if builder == "pdfhtml": print_func(f"Finished generating HTML for {cmd_type}...") print_func(f"Converting {cmd_type} HTML into PDF...") path_pdf_output = output_path.parent.joinpath("pdf") path_pdf_output.mkdir(exist_ok=True) if cmd_type == "book": path_pdf_output = path_pdf_output.joinpath("book.pdf") html_to_pdf(output_path.joinpath("index.html"), path_pdf_output) elif cmd_type == "page": path_pdf_output = path_pdf_output.joinpath(page_name + ".pdf") html_to_pdf(output_path.joinpath(page_name + ".html"), path_pdf_output) path_pdf_output_rel = Path(op.relpath(path_pdf_output, Path())) _message_box(f"""\ Finished generating PDF via HTML for {cmd_type}. Your PDF is here: {path_pdf_output_rel}\ """) if builder == "pdflatex": print_func(f"Finished generating latex for {cmd_type}...") print_func(f"Converting {cmd_type} latex into PDF...") # Convert to PDF via tex and template built Makefile and make.bat if sys.platform == "win32": makecmd = os.environ.get("MAKE", "make.bat") else: makecmd = os.environ.get("MAKE", "make") try: with cd(output_path): output = subprocess.run([makecmd, "all-pdf"]) if output.returncode != 0: _error("Error: Failed to build pdf") return output.returncode _message_box(f"""\ A PDF of your {cmd_type} can be found at: {output_path} """) except OSError: _error("Error: Failed to run: %s" % makecmd) return 1