簡體   English   中英

在 yaml 中聲明 python 模塊

[英]Declare python module in yaml

我有一個 yaml 文件,其中有一些字段的值在 python 中是可以理解的,但是它們被解析為字符串值,而不是我的意思是 python 類型。 這是我的樣本:

verbose:
   level: logging.DEBUG

很明顯,當我加載它時,該值是字符串類型

config = yaml.load(args.config.read(), Loader=yaml.SafeLoader)

我不知道如何准確獲取logging.DEBUG對象,而不是它的字符串。

請注意,我不尋找配置日志來獲取記錄器的東西。 此日志記錄只是 python 模塊的一個示例。

沒有開箱即用的方法。 最簡單和最安全的方法似乎是手動處理值,例如:

import logging

class KnownModules:
    logging = logging
    ...


def parse_value(s):
    v = KnownModules
    for p in s.split('.'):
        v = getattr(v, p)  # remember to handle AttributeError
    return v

但是,如果您可以稍微更改 YAML 結構,PyYAML 支持一些自定義 YAML 標簽 例如:

verbose:
    level: !!python/name:logging.DEBUG

將使config['verbose']['level']等於logging.DEBUG (即10 )。

考慮到您(正確)使用SafeLoader ,您可能需要通過定義自己的標簽來組合這些方法。

編輯:請參閱 AKX 答案。 我不知道logging._nameToLevel不需要定義自己的 enum 並且絕對比使用evel更好。 但是,我決定不刪除此答案,因為我認為使用枚舉的當前首選設計(從 python 3.4 開始)值得一提(如果當時可用,它可能會在日志記錄模塊中使用)。


如果您絕對確定配置中提供的值是合法的,您可以像這樣使用eval

import logging
levelStr = 'logging.DEBUG'
level = eval(levelStr)

但正如評論中所說,如果您不確定配置文件中存在的值,使用eval可能是災難性的(請參閱 AKX 在評論中提供的示例)。

更好的設計是為此目的定義一個枚舉。 不幸的是,日志模塊不提供枚舉級別(它們只是模塊中定義的常量),因此您應該定義自己的級別。

from enum import Enum
class LogLevel(Enum):
    CRITICAL = 50
    FATAL = 50
    ERROR = 40
    WARNING = 30
    WARN = 30
    INFO = 20
    DEBUG = 10
    NOTSET = 0

然后你可以像這樣使用它:

levelStr = 'DEBUG'
levelInt = LogLevel[levelStr].value # Comparable with logging.DEBUG which is also an integer

但是要使用它,您必須稍微更改 yml 文件並將logging.DEBUG替換為DEBUG

YAML 加載器不知道logging.DEBUG可能意味着什么,除了字符串"logging.DEBUG" (除非它被標記為 YAML 標簽)。

對於需要解釋為例如對模塊屬性的引用的字符串值,您需要事后解析它們,例如

def parse_logging_level(level_string: str):
    module, _, value = level_string.partition(".")
    assert module == "logging"
    return logging._nameToLevel[value]

# ...

yaml_data["verbose"]["level"] = parse_logging_level(yaml_data["verbose"]["level"])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM