diff --git a/docs/how_to_guides/configuring.rst b/docs/how_to_guides/configuring.rst index ab3a07cb..93c4e3a0 100644 --- a/docs/how_to_guides/configuring.rst +++ b/docs/how_to_guides/configuring.rst @@ -132,9 +132,9 @@ keyfile ``--keyfile`` Path to the SSL key fil keyfile_password ``--keyfile-password`` Password for the keyfile if the keyfile is password-protected. logconfig ``--log-config`` A Python logging configuration file. This The logging ini format. - can be prefixed with 'json:' or 'toml:' to - load the configuration from a file in that - format. + can be prefixed with 'json:', 'yaml:' + or 'toml:' to load the configuration from + a file in that format. logconfig_dict N/A A Python logging configuration dictionary. logger_class N/A Type of class to use for logging. loglevel ``--log-level`` The (error) log level. ``INFO`` diff --git a/docs/how_to_guides/logging.rst b/docs/how_to_guides/logging.rst index 9e16e079..0b2ef9a2 100644 --- a/docs/how_to_guides/logging.rst +++ b/docs/how_to_guides/logging.rst @@ -20,7 +20,7 @@ The ``logconfig`` variable should point at a file to be used by the ``fileConfig`` function. Alternatively it can point to a JSON or TOML formatted file which will be loaded and passed to the ``dictConfig`` function. To use a JSON formatted file prefix the filepath with -``json:`` and for TOML use ``toml:``. +``json:``, for TOML use ``toml:`` and ``yaml:`` for YAML. Configuring access logs ----------------------- diff --git a/pyproject.toml b/pyproject.toml index 7a6b6a84..94e8c3cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ repository = "https://github.com/pgjones/hypercorn/" documentation = "https://hypercorn.readthedocs.io" [tool.poetry.dependencies] -python = ">=3.8" +python = ">=3.9" aioquic = { version = ">= 0.9.0, < 1.0", optional = true } exceptiongroup = { version = ">= 1.1.0", python = "<3.11" } h11 = "*" @@ -40,6 +40,7 @@ trio = { version = ">=0.22.0", optional = true } typing_extensions = { version = "*", python = "<3.11" } uvloop = { version = ">=0.18", markers = "platform_system != 'Windows'", optional = true } wsproto = ">=0.14.0" +pyyaml = { version = ">=6.0.0", optional = true } [tool.poetry.dev-dependencies] httpx = "*" diff --git a/src/hypercorn/__main__.py b/src/hypercorn/__main__.py index aed33b12..67df1b41 100644 --- a/src/hypercorn/__main__.py +++ b/src/hypercorn/__main__.py @@ -16,9 +16,9 @@ def _load_config(config_path: Optional[str]) -> Config: if config_path is None: return Config() elif config_path.startswith("python:"): - return Config.from_object(config_path[len("python:") :]) + return Config.from_object(config_path[len("python:"):]) elif config_path.startswith("file:"): - return Config.from_pyfile(config_path[len("file:") :]) + return Config.from_pyfile(config_path[len("file:"):]) else: return Config.from_toml(config_path) @@ -136,7 +136,7 @@ def main(sys_args: Optional[List[str]] = None) -> int: parser.add_argument( "--log-config", help=""""A Python logging configuration file. This can be prefixed with - 'json:' or 'toml:' to load the configuration from a file in + 'json:', 'yaml:' (pyyaml required) or 'toml:' to load the configuration from a file in that format. Default is the logging ini format.""", default=sentinel, ) diff --git a/src/hypercorn/logging.py b/src/hypercorn/logging.py index d9b8901a..74e490e8 100644 --- a/src/hypercorn/logging.py +++ b/src/hypercorn/logging.py @@ -7,7 +7,18 @@ import time from http import HTTPStatus from logging.config import dictConfig, fileConfig -from typing import Any, IO, Mapping, Optional, TYPE_CHECKING, Union +from typing import IO, TYPE_CHECKING, Any, Mapping, Optional, Union + +yaml = None +try: + import importlib.util + + spec = importlib.util.find_spec("yaml") + if spec is not None: + yaml = importlib.import_module("yaml") + +except ImportError: + yaml = None if sys.version_info >= (3, 11): import tomllib @@ -68,6 +79,14 @@ def __init__(self, config: "Config") -> None: if config.logconfig.startswith("json:"): with open(config.logconfig[5:]) as file_: dictConfig(json.load(file_)) + elif config.logconfig.startswith("yaml:"): + if not yaml: + raise ValueError( + "pyyaml is not installed, cannot load yaml config, " + "see https://pypi.org/project/PyYAML/ for more information", + ) + with open(config.logconfig[5:]) as file_: + dictConfig(yaml.safe_load(file_)) elif config.logconfig.startswith("toml:"): with open(config.logconfig[5:], "rb") as file_: dictConfig(tomllib.load(file_))