Python 带有 env 变量的 ConfigParser 和字符串插值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26586801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:42:48  来源:igfitidea点击:

ConfigParser and String interpolation with env variable

pythonconfigparser

提问by nkint

it's a little bit I'm out of python syntax and I have a problem in reading a .inifile with interpolated values.

我有点不了解 python 语法,并且在读取.ini带有内插值的文件时遇到问题。

this is my ini file:

这是我的ini文件:

[DEFAULT]
home=$HOME
test_home=$home

[test]
test_1=$test_home/foo.csv
test_2=$test_home/bar.csv

Those lines

那些线

from ConfigParser import SafeConfigParser

parser = SafeConfigParser()
parser.read('config.ini')

print parser.get('test', 'test_1')

does output

输出

$test_home/foo.csv

while I'm expecting

在我期待的时候

/Users/nkint/foo.csv

EDIT:

编辑:

I supposed that the $syntax was implicitly included in the so called string interpolation(referring to the manual):

我认为该$语法隐式包含在所谓的字符串插值中(参考手册):

On top of the core functionality, SafeConfigParser supports interpolation. This means values can contain format strings which refer to other values in the same section, or values in a special DEFAULT section.

除了核心功能之外,SafeConfigParser 还支持插值。这意味着值可以包含引用同一部分中其他值的格式字符串,或特殊 DEFAULT 部分中的值。

But I'm wrong. How to handle this case?

但我错了。这个案子怎么处理?

采纳答案by Michele d'Amico

First of all according to the documentation you should use %(test_home)sto interpolate test_home. Moreover the key are case insensitive and you can't use both HOMEand homekeys. Finally you can use SafeConfigParser(os.environ)to take in account of you environment.

首先,根据您应该%(test_home)s用来插值的文档test_home。此外,键不区分大小写,并且不能同时使用HOMEhome键。最后,您可以使用SafeConfigParser(os.environ)来考虑您的环境。

from ConfigParser import SafeConfigParser
import os


parser = SafeConfigParser(os.environ)
parser.read('config.ini')

Where config.iniis

哪里config.ini

[DEFAULT]
test_home=%(HOME)s

[test]
test_1=%(test_home)s/foo.csv
test_2=%(test_home)s/bar.csv

回答by Mauro Baraldi

ConfigParser.getvalues are strings, even if you set values as integer or True. But ConfigParser has getint, getfloatand getboolean.

ConfigParser.get值是字符串,即使您将值设置为整数或 True。但是 ConfigParser 有getintgetfloatgetboolean

settings.ini

设置文件

[default]
home=/home/user/app
tmp=%(home)s/tmp
log=%(home)s/log
sleep=10
debug=True

config reader

配置阅读器

>>> from ConfigParser import SafeConfigParser
>>> parser = SafeConfigParser()
>>> parser.read('/home/user/app/settings.ini')
>>> parser.get('defaut', 'home')
'/home/user/app'
>>> parser.get('defaut', 'tmp')
'/home/user/app/tmp'
>>> parser.getint('defaut', 'sleep')
10
>>> parser.getboolean('defaut', 'debug')
True

Edit

编辑

Indeed you could get name values as environ var if you initialize SafeConfigParserwith os.environ. Thanks for the Michele'sanswer.

实际上,如果您SafeConfigParser使用os.environ. 感谢米歇尔的回答。

回答by gagnonlg

If you want to expand some environment variables, you can do so using os.path.expandvarsbefore parsing a StringIOstream:

如果要扩展一些环境变量,可以os.path.expandvars在解析StringIO流之前使用:

import ConfigParser
import os
import StringIO

with open('config.ini', 'r') as cfg_file:
    cfg_txt = os.path.expandvars(cfg_file.read())

config = ConfigParser.ConfigParser()
config.readfp(StringIO.StringIO(cfg_txt))

回答by MrE

the trick for proper variable substitution from environment is to use the ${} syntax for the environment variables:

从环境中正确替换变量的技巧是对环境变量使用 ${} 语法:

[DEFAULT]
test_home=${HOME}

[test]
test_1=%(test_home)s/foo.csv
test_2=%(test_home)s/bar.csv

回答by Alex Markov

You can write custom interpolation in case of Python 3:

在 Python 3 的情况下,您可以编写自定义插值:

import configparser
import os


class EnvInterpolation(configparser.BasicInterpolation):
    """Interpolation which expands environment variables in values."""

    def before_get(self, parser, section, option, value, defaults):
        return os.path.expandvars(value)


cfg = """
[section1]
key = value
my_path = $PATH
"""

config = configparser.ConfigParser(interpolation=EnvInterpolation())
config.read_string(cfg)
print(config['section1']['my_path'])

回答by Franzi

It seems in the last version 3.5.0, ConfigParser was not reading the env variables, so I end up providing a custom Interpolation based on the BasicInterpolationone.

似乎在最后一个版本中3.5.0,ConfigParser 没有读取 env 变量,因此我最终提供了基于该变量的自定义插值BasicInterpolation

class EnvInterpolation(BasicInterpolation):
    """Interpolation as implemented in the classic ConfigParser,
    plus it checks if the variable is provided as an environment one in uppercase.
    """

    def _interpolate_some(self, parser, option, accum, rest, section, map,
                          depth):
        rawval = parser.get(section, option, raw=True, fallback=rest)
        if depth > MAX_INTERPOLATION_DEPTH:
            raise InterpolationDepthError(option, section, rawval)
        while rest:
            p = rest.find("%")
            if p < 0:
                accum.append(rest)
                return
            if p > 0:
                accum.append(rest[:p])
                rest = rest[p:]
            # p is no longer used
            c = rest[1:2]
            if c == "%":
                accum.append("%")
                rest = rest[2:]
            elif c == "(":
                m = self._KEYCRE.match(rest)
                if m is None:
                    raise InterpolationSyntaxError(option, section,
                                                   "bad interpolation variable reference %r" % rest)
                var = parser.optionxform(m.group(1))
                rest = rest[m.end():]
                try:
                    v = os.environ.get(var.upper())
                    if v is None:
                        v = map[var]
                except KeyError:
                    raise InterpolationMissingOptionError(option, section, rawval, var) from None
                if "%" in v:
                    self._interpolate_some(parser, option, accum, v,
                                           section, map, depth + 1)
                else:
                    accum.append(v)
            else:
                raise InterpolationSyntaxError(
                    option, section,
                    "'%%' must be followed by '%%' or '(', "
                    "found: %r" % (rest,))

The difference between the BasicInterpolationand the EnvInterpolationis in:

之间的差异BasicInterpolationEnvInterpolation具体表现在:

   v = os.environ.get(var.upper())
   if v is None:
       v = map[var]

where I'm trying to find the varin the enviornment before checking in the map.

在那里我试图找到var在检查前的enviornment map

回答by L0ngSh0t

Quite late, but maybe it can help someone else looking for the same answers that I had recently. Also, one of the comments was how to fetch Environment variables and values from other sections. Here is how I deal with both converting environment variables and multi-section tags when reading in from an INI file.

很晚了,但也许它可以帮助其他人寻找与我最近相同的答案。此外,评论之一是如何从其他部分获取环境变量和值。下面是我在从 INI 文件读入时处理转换环境变量和多节标记的方法。

INI FILE:

INI文件:

[PKG]
# <VARIABLE_NAME>=<VAR/PATH>
PKG_TAG = Q1_RC1

[DELIVERY_DIRS]
# <DIR_VARIABLE>=<PATH>
NEW_DELIVERY_DIR=${DEL_PATH}\ProjectName_${PKG:PKG_TAG}_DELIVERY

Python Class that uses the ExtendedInterpolation so that you can use the ${PKG:PKG_TAG}type formatting. I add the ability to convert the windows environment vars when I read in INI to a string using the builtin os.path.expandvars()function such as ${DEL_PATH}above.

使用 ExtendedInterpolation 的 Python 类,以便您可以使用${PKG:PKG_TAG}类型格式。当我使用上述内置os.path.expandvars()函数将 INI 读入字符串时,我添加了将 Windows 环境变量转换为字符串的功能${DEL_PATH}

import os
from configparser import ConfigParser, ExtendedInterpolation

class ConfigParser(object):

    def __init__(self):
        """
        initialize the file parser with
        ExtendedInterpolation to use ${Section:option} format
        [Section]
        option=variable
        """
        self.config_parser = ConfigParser(interpolation=ExtendedInterpolation())

    def read_ini_file(self, file='./config.ini'):
        """
        Parses in the passed in INI file and converts any Windows environ vars.

        :param file: INI file to parse
        :return: void
        """
        # Expands Windows environment variable paths
        with open(file, 'r') as cfg_file:
            cfg_txt = os.path.expandvars(cfg_file.read())

        # Parses the expanded config string
        self.config_parser.read_string(cfg_txt)

    def get_config_items_by_section(self, section):
        """
        Retrieves the configurations for a particular section

        :param section: INI file section
        :return: a list of name, value pairs for the options in the section
        """
        return self.config_parser.items(section)

    def get_config_val(self, section, option):
        """
        Get an option value for the named section.

        :param section: INI section
        :param option: option tag for desired value
        :return: Value of option tag
        """
        return self.config_parser.get(section, option)

    @staticmethod
    def get_date():
        """
        Sets up a date formatted string.

        :return: Date string
        """
        return datetime.now().strftime("%Y%b%d")

    def prepend_date_to_var(self, sect, option):
        """
        Function that allows the ability to prepend a
        date to a section variable.

        :param sect: INI section to look for variable
        :param option: INI search variable under INI section
        :return: Void - Date is prepended to variable string in INI
        """
        if self.config_parser.get(sect, option):
            var = self.config_parser.get(sect, option)
            var_with_date = var + '_' + self.get_date()
            self.config_parser.set(sect, option, var_with_date)