Preservar caso no ConfigParser?

90

Tentei usar o módulo ConfigParser do Python para salvar as configurações. Para meu aplicativo, é importante que eu preserve a caixa de cada nome em minhas seções. Os documentos mencionam que passar str () para ConfigParser.optionxform () faria isso, mas não funciona para mim. Os nomes estão todos em minúsculas. Estou esquecendo de algo?

<~/.myrc contents>
[rules]
Monkey = foo
Ferret = baz

Pseudocódigo Python do que obtenho:

import ConfigParser,os

def get_config():
   config = ConfigParser.ConfigParser()
   config.optionxform(str())
    try:
        config.read(os.path.expanduser('~/.myrc'))
        return config
    except Exception, e:
        log.error(e)

c = get_config()  
print c.options('rules')
[('monkey', 'foo'), ('ferret', 'baz')]
pojo
fonte

Respostas:

114

A documentação é confusa. O que eles querem dizer é:

import ConfigParser, os
def get_config():
    config = ConfigParser.ConfigParser()
    config.optionxform=str
    try:
        config.read(os.path.expanduser('~/.myrc'))
        return config
    except Exception, e:
        log.error(e)

c = get_config()  
print c.options('rules')

Ou seja, substituir optionxform, em vez de chamá-lo; a sobreposição pode ser feita em uma subclasse ou na instância. Ao substituir, defina-o como uma função (em vez do resultado da chamada de uma função).

Agora eu relatei isso como um bug , e desde então foi corrigido.

Martin v. Löwis
fonte
Obrigado. Funciona e concordo que os documentos são confusos.
pojo
39

Para mim, trabalhei para definir o optionxform imediatamente após criar o objeto

config = ConfigParser.RawConfigParser()
config.optionxform = str 
ulitosCoder
fonte
2
Funciona bem! (observe que no python 3 é o nome da classe "configparser" (sem maiúsculas)
Noam Manos
1
@NoamManos: Você está se referindo ao nome do módulo (o nome da classe ainda é ConfigParser ).
Jonas Byström
2
Observe que também funciona comConfigParser.ConfigParser()
Jean-François T.
De fato. Funciona. É bom mencionar que este parâmetro não está associado essencialmente a RawConfigParser (), já que também é compatível com a classe ConfigParser (). Obrigado cara.
ivanleoncz
7

Adicione ao seu código:

config.optionxform = lambda option: option  # preserve case for letters
FooBar167
fonte
1
Isso parece funcionar para mim pelo menos no python 2.7 e é muito mais limpo do que a resposta aceita. Obrigado foo!
hrbdg
2
esta é a mesma resposta com pontuação mais alta - ver linha config.optionxform=str:) apenas em vez de lamdba @Martin v. Löwis usa strfunção incorporada
xuthus
@xuthus - Na verdade, você pode usar 11 linhas de código em vez de 1 linha. Como você quiser.
FooBar167
4

Eu sei que esta pergunta foi respondida, mas pensei que algumas pessoas poderiam achar esta solução útil. Esta é uma classe que pode facilmente substituir a classe ConfigParser existente.

Editado para incorporar a sugestão de @OozeMeister:

class CaseConfigParser(ConfigParser):
    def optionxform(self, optionstr):
        return optionstr

O uso é igual ao do ConfigParser normal.

parser = CaseConfigParser()
parser.read(something)

Isso evita ter que definir o optionxform toda vez que fizer um novo ConfigParser, o que é entediante.

árvores de gelo
fonte
Como optionxformé apenas um método no RawConfigParser, se você for tão longe quanto criar sua própria subclasse, você deve apenas substituir o método na subclasse em vez de redefini-lo por instanciação:class CaseConfigParser(ConfigParser): def optionxform(self, optionstr): return optionstr
OozeMeister
@OozeMeister ótima ideia!
icedtrees de
2

Embargo:

Se você usar padrões com ConfigParser, ou seja:

config = ConfigParser.SafeConfigParser({'FOO_BAZ': 'bar'})

e tente tornar o analisador sensível a maiúsculas e minúsculas usando o seguinte:

config.optionxform = str

todas as opções do (s) arquivo (s) de configuração manterão a caixa, mas FOO_BAZserão convertidas em minúsculas.

Para que os padrões também mantenham o caso, use subclasses como na resposta @icedtrees:

class CaseConfigParser(ConfigParser.SafeConfigParser):
    def optionxform(self, optionstr):
        return optionstr

config = CaseConfigParser({'FOO_BAZ': 'bar'})

Agora FOO_BAZmanterá a caixa e você não terá InterpolationMissingOptionError .

nidalpres
fonte