Open2

Python で気になった機能の中身をみてみる。

うさぎになりたいもぐら(←理想図)うさぎになりたいもぐら(←理想図)

Sphinxで設定をかきこむconf.pyをどうやってよみこんでいるのか

https://github.com/sphinx-doc/sphinx

Python製ドキュメント作成ツール

ここにあった

必要なところだけとると

#L33
CONFIG_FILENAME = 'conf.py'

#L74
class Config:
    config_values: Dict[str, Tuple] 

    #L543
    def __init__(self, config: Dict[str, Any] = {}, overrides: Dict[str, Any] = {}) -> None:
        self.overrides = dict(overrides)
        self.values = Config.config_values.copy()
        self._raw_config = config
        self.setup: Optional[Callable] = config.get('setup', None)

        if 'extensions' in self.overrides:
            if isinstance(self.overrides['extensions'], str):
                config['extensions'] = self.overrides.pop('extensions').split(',')
            else:
                config['extensions'] = self.overrides.pop('extensions')
        self.extensions: List[str] = config.get('extensions', [])

    @classmethod
    def read(cls, confdir: str, overrides: Dict = None, tags: Tags = None) -> "Config":
        """Create a Config object from configuration file."""
        filename = path.join(confdir, CONFIG_FILENAME)
        if not path.isfile(filename):
            raise ConfigError(__("config directory doesn't contain a conf.py file (%s)") %
                              confdir)
        namespace = eval_config_file(filename, tags)
        return cls(namespace, overrides or {})

#L318
def eval_config_file(filename: str, tags: Optional[Tags]) -> Dict[str, Any]:
    """Evaluate a config file."""
    namespace: Dict[str, Any] = {}
    namespace['__file__'] = filename
    namespace['tags'] = tags

    with cd(path.dirname(filename)):
        # during executing config file, current dir is changed to ``confdir``.
        try:
            with open(filename, 'rb') as f:
                code = compile(f.read(), filename.encode(fs_encoding), 'exec')
                exec(code, namespace)
        except SyntaxError as err:
            msg = __("There is a syntax error in your configuration file: %s\n")
            raise ConfigError(msg % err) from err
        except SystemExit as exc:
            msg = __("The configuration file (or one of the modules it imports) "
                     "called sys.exit()")
            raise ConfigError(msg) from exc
        except ConfigError:
            # pass through ConfigError from conf.py as is.  It will be shown in console.
            raise
        except Exception as exc:
            msg = __("There is a programmable error in your configuration file:\n\n%s")
            raise ConfigError(msg % traceback.format_exc()) from exc

    return namespace

compile exec よくしらないな調べよう

うさぎになりたいもぐら(←理想図)うさぎになりたいもぐら(←理想図)

conf.py

conf.py

import sphinx

extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
              'sphinx.ext.autosummary', 'sphinx.ext.extlinks',
              'sphinx.ext.intersphinx',
              'sphinx.ext.viewcode', 'sphinx.ext.inheritance_diagram']

root_doc = 'contents'

#ect.

となっている conf.py をcomplie,execしている

exec実行時、globals にnamespaceをいれることで、conf.py内で代入された値をdictとして取得している

簡単にかくと、

CONFIG_FILENAME = 'conf.py'
namespace: Dict[str, Any] = {} 
with open(filename, 'rb') as f:
    code = compile(f.read(), filename.encode(fs_encoding), 'exec')
    exec(code, namespace)
#そして、namespaceなどを引数にしてConfigインスタンスが生成されると。