2010-05-21 42 views
60

Tôi đang sử dụng ConfigParser để đọc cấu hình thời gian chạy của tập lệnh.Sử dụng ConfigParser của Python để đọc tệp không có tên phần

Tôi muốn có sự linh hoạt khi không cung cấp tên phần (có các kịch bản đủ đơn giản; chúng không cần 'phần'). ConfigParser sẽ ném ngoại lệ NoSectionError và sẽ không chấp nhận tệp.

Làm cách nào để tôi có thể đặt ConfigParser chỉ cần truy xuất (key, value) bộ dữ liệu của tệp cấu hình không có tên phần? Ví dụ:

key1=val1 
key2:val2 

Tôi không muốn ghi vào tệp cấu hình.

Trả lời

33

Alex Martelli provided a solution để sử dụng ConfigParser để phân tích cú pháp .properties tệp (các tệp cấu hình dường như ít phần).

His solution là trình bao bọc giống như tệp sẽ tự động chèn tiêu đề phần giả để đáp ứng các yêu cầu của ConfigParser.

+0

+1 vì đó là chính xác những gì tôi sắp đề nghị. Tại sao thêm tất cả sự phức tạp khi tất cả những gì bạn phải làm chỉ là thêm một phần! – jathanism

+2

@jathanism: có những trường hợp bạn muốn làm việc với các tệp cấu hình/thuộc tính hiện có, được đọc bằng mã Java hiện có và bạn không biết rủi ro sửa đổi các tiêu đề đó là – Tshepang

+0

được truyền cảm hứng rất nhiều! –

12

Bạn có thể sử dụng thư viện ConfigObj để làm điều đó chỉ đơn giản là: http://www.voidspace.org.uk/python/configobj.html

Cập nhật: Tìm mã mới nhất here.

Nếu bạn dưới Debian/Ubuntu, bạn có thể cài đặt module này sử dụng quản lý gói của bạn:

apt-get install python-configobj 

Một ví dụ về sử dụng:

from configobj import ConfigObj 

config = ConfigObj('myConfigFile.ini') 
config.get('key1') # You will get val1 
config.get('key2') # You will get val2 
6

Sau khi chạy vào vấn đề này bản thân mình, tôi đã viết một trình bao bọc hoàn chỉnh cho ConfigParser (phiên bản trong Python 2) có thể đọc và ghi các tệp mà không cần phần minh bạch, dựa trên cách tiếp cận của Alex Martelli được liên kết trên câu trả lời được chấp nhận. Nó phải là một sự thay thế cho bất kỳ việc sử dụng nào của ConfigParser. Đăng nó trong trường hợp bất cứ ai có nhu cầu tìm thấy trang này.

import ConfigParser 
import StringIO 

class SectionlessConfigParser(ConfigParser.RawConfigParser): 
    """ 
    Extends ConfigParser to allow files without sections. 

    This is done by wrapping read files and prepending them with a placeholder 
    section, which defaults to '__config__' 
    """ 

    def __init__(self, *args, **kwargs): 
     default_section = kwargs.pop('default_section', None) 
     ConfigParser.RawConfigParser.__init__(self, *args, **kwargs) 

     self._default_section = None 
     self.set_default_section(default_section or '__config__') 

    def get_default_section(self): 
     return self._default_section 

    def set_default_section(self, section): 
     self.add_section(section) 

     # move all values from the previous default section to the new one 
     try: 
      default_section_items = self.items(self._default_section) 
      self.remove_section(self._default_section) 
     except ConfigParser.NoSectionError: 
      pass 
     else: 
      for (key, value) in default_section_items: 
       self.set(section, key, value) 

     self._default_section = section 

    def read(self, filenames): 
     if isinstance(filenames, basestring): 
      filenames = [filenames] 

     read_ok = [] 
     for filename in filenames: 
      try: 
       with open(filename) as fp: 
        self.readfp(fp) 
      except IOError: 
       continue 
      else: 
       read_ok.append(filename) 

     return read_ok 

    def readfp(self, fp, *args, **kwargs): 
     stream = StringIO() 

     try: 
      stream.name = fp.name 
     except AttributeError: 
      pass 

     stream.write('[' + self._default_section + ']\n') 
     stream.write(fp.read()) 
     stream.seek(0, 0) 

     return ConfigParser.RawConfigParser.readfp(self, stream, *args, 
                **kwargs) 

    def write(self, fp): 
     # Write the items from the default section manually and then remove them 
     # from the data. They'll be re-added later. 
     try: 
      default_section_items = self.items(self._default_section) 
      self.remove_section(self._default_section) 

      for (key, value) in default_section_items: 
       fp.write("{0} = {1}\n".format(key, value)) 

      fp.write("\n") 
     except ConfigParser.NoSectionError: 
      pass 

     ConfigParser.RawConfigParser.write(self, fp) 

     self.add_section(self._default_section) 
     for (key, value) in default_section_items: 
      self.set(self._default_section, key, value) 
34

giác ngộ bởi this answer by jterrace, tôi đưa ra giải pháp này:

  1. đã đọc toàn bộ tập tin vào một chuỗi
  2. Prefix với một tên phần mặc định
  3. Sử dụng StringIO để bắt chước một tập tin giống như đối tượng
ini_str = '[root]\n' + open(ini_path, 'r').read() 
ini_fp = StringIO.StringIO(ini_str) 
config = ConfigParser.RawConfigParser() 
config.readfp(ini_fp) 
+0

Điều này cũng làm việc kỳ diệu để phân tích một Makefile đơn giản (chỉ với bí danh)! [Đây là một kịch bản đầy đủ để thay thế bí danh bằng lệnh đầy đủ của họ bằng Python] (https://github.com/tqdm/tqdm/commit/7405a59ff2f1986922393c2bec77fced9932b28e#diff-2eeaed663bd0d25b7e608891384b7298R15), lấy cảm hứng từ câu trả lời này. – gaborous

6

Cách dễ nhất để làm điều này là sử dụng trình phân tích CSV của python, theo ý kiến ​​của tôi. Đây là một chức năng đọc/ghi thể hiện cách tiếp cận này cũng như một trình điều khiển thử nghiệm. Điều này sẽ hoạt động được cung cấp các giá trị không được phép là nhiều dòng. :)

import csv 
import operator 

def read_properties(filename): 
    """ Reads a given properties file with each line of the format key=value. Returns a dictionary containing the pairs. 

    Keyword arguments: 
     filename -- the name of the file to be read 
    """ 
    result={ } 
    with open(filename, "rb") as csvfile: 
     reader = csv.reader(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE) 
     for row in reader: 
      if len(row) != 2: 
       raise csv.Error("Too many fields on row with contents: "+str(row)) 
      result[row[0]] = row[1] 
    return result 

def write_properties(filename,dictionary): 
    """ Writes the provided dictionary in key-sorted order to a properties file with each line of the format key=value 

    Keyword arguments: 
     filename -- the name of the file to be written 
     dictionary -- a dictionary containing the key/value pairs. 
    """ 
    with open(filename, "wb") as csvfile: 
     writer = csv.writer(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE) 
     for key, value in sorted(dictionary.items(), key=operator.itemgetter(0)): 
       writer.writerow([ key, value]) 

def main(): 
    data={ 
     "Hello": "5+5=10", 
     "World": "Snausage", 
     "Awesome": "Possum" 
    } 

    filename="test.properties" 
    write_properties(filename,data) 
    newdata=read_properties(filename) 

    print "Read in: " 
    print newdata 
    print 

    contents="" 
    with open(filename, 'rb') as propfile: 
     contents=propfile.read() 
    print "File contents:" 
    print contents 

    print ["Failure!", "Success!"][data == newdata] 
    return 

if __name__ == '__main__': 
    main() 
+0

+1 Sử dụng thông minh của mô-đun 'csv' để giải quyết khiếu nại' ConfigParser' phổ biến. Dễ dàng tổng quát hơn và được tạo thành [cả Python 2 & 3 tương thích] (http://stackoverflow.com/a/17796539/355230). – martineau

27

Bạn có thể thực hiện việc này bằng một dòng mã bổ sung. (Hai dòng nếu bạn đếm import câu lệnh.)

Trong python 3, sử dụng itertools.chain() để mô phỏng đầu trang phần cho read_file().

from configparser import ConfigParser 
from itertools import chain 

parser = ConfigParser() 
with open("foo.conf") as lines: 
    lines = chain(("[top]",), lines) # This line does the trick. 
    parser.read_file(lines) 

Trong python 2, thêm vào trước một dòng phần tiêu đề để các dữ liệu bạn đọc từ tập tin cấu hình của bạn, quấn kết quả trong một đối tượng StringIO, và vượt qua nó để readfp().

from ConfigParser import ConfigParser 
from StringIO import StringIO 

parser = ConfigParser() 
with open("foo.conf") as stream: 
    stream = StringIO("[top]\n" + stream.read()) # This line does the trick. 
    parser.readfp(stream) 

Với cách tiếp cận, cài đặt cấu hình của bạn sẽ có sẵn trong parser.items('top').

Bạn cũng có thể sử dụng StringIO trong python 3 bằng cách nhập nó từ nhà mới trong gói io, nhưng lưu ý rằng readfp() không được dùng trong python 3 và do đó nên tránh.

5

Blueicefield của câu trả lời nêu configobj, nhưng lib gốc chỉ hỗ trợ Python 2. Nó bây giờ có một Python 3+ tương thích cổng:

https://github.com/DiffSK/configobj

API đã không thay đổi, nhìn thấy nó là doc.

1

configobj lib có thể giúp trong trường hợp KEY="value"

from configobj import ConfigObj 
cfg = ConfigObj('/home/.aws/config') 
access_key_id = cfg['aws_access_key_id'] 
secret_access_key = cfg['aws_secret_access_key'] 
+3

Dường như là một bản sao của câu trả lời của @ Blueicefield. –

Các vấn đề liên quan