From 57bf3d829ed57d41e43559116ac156762b1cf01a Mon Sep 17 00:00:00 2001 From: Ilia Dmitriev Date: Tue, 7 May 2024 16:31:35 +0300 Subject: [PATCH 1/3] add yaml support --- pyproject.toml | 3 ++- src/hypercorn/logging.py | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 37d199df..a74e638a 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 = ">= 1.1.0" h11 = "*" @@ -39,6 +39,7 @@ tomli = { version = "*", python = "<3.11" } trio = { version = ">=0.22.0", optional = true } uvloop = { version = "*", markers = "platform_system != 'Windows'", optional = true } wsproto = ">=0.14.0" +pyyaml = ">=6.0.0" [tool.poetry.dev-dependencies] hypothesis = "*" diff --git a/src/hypercorn/logging.py b/src/hypercorn/logging.py index d9b8901a..5bcf7d78 100644 --- a/src/hypercorn/logging.py +++ b/src/hypercorn/logging.py @@ -9,6 +9,8 @@ from logging.config import dictConfig, fileConfig from typing import Any, IO, Mapping, Optional, TYPE_CHECKING, Union +import yaml + if sys.version_info >= (3, 11): import tomllib else: @@ -68,6 +70,9 @@ 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:"): + 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_)) From 20b2ecb7ecfe6a561334bdb815bc78b231e6d0f3 Mon Sep 17 00:00:00 2001 From: Ilia Dmitriev Date: Tue, 7 May 2024 16:36:57 +0300 Subject: [PATCH 2/3] added docs --- docs/how_to_guides/configuring.rst | 6 +++--- docs/how_to_guides/logging.rst | 2 +- src/hypercorn/__main__.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) 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/src/hypercorn/__main__.py b/src/hypercorn/__main__.py index aed33b12..19d0ca7f 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:' or 'toml:' to load the configuration from a file in that format. Default is the logging ini format.""", default=sentinel, ) From 49b65b750cd153cd35bd73267c545bcf35e33c60 Mon Sep 17 00:00:00 2001 From: Ilia Dmitriev Date: Mon, 14 Apr 2025 15:56:00 +0300 Subject: [PATCH 3/3] made pyyaml optional, with error message --- pyproject.toml | 2 +- src/hypercorn/__main__.py | 2 +- src/hypercorn/logging.py | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dbb3cf9c..94e8c3cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +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 = ">=6.0.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 19d0ca7f..67df1b41 100644 --- a/src/hypercorn/__main__.py +++ b/src/hypercorn/__main__.py @@ -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:', 'yaml:' 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 5bcf7d78..74e490e8 100644 --- a/src/hypercorn/logging.py +++ b/src/hypercorn/logging.py @@ -7,9 +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 -import yaml +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 @@ -71,6 +80,11 @@ def __init__(self, config: "Config") -> None: 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:"):