Is there an attribute to lock a ConfigParser object in read-inly mode ?

I'm using a project-wide global ConfigParser object and I want to prevent the code from modifying the object. I could easily override ConfigParser.set(section,option,value) to raise an error if the method is called, but I'm wondering if I haven't overlooked a simpler solution.

有帮助吗?

解决方案

I've found a generic solution to this problem (using this fantastic snippet written by Felix Kling here : How to create a constant in Python ). My aim is to simplify the debugger's job, using a bit of defensive programming, not to prevent any malicious access of the class.

Moreover, it's kind of hackish : constant members and private/protected access are does get along well with Python's philosophy ('explicit better than implicit' , ...).


Phase 1 : Block setters

First, we have to block any setters from ConfigParse : easy peasy, we just have to override set(self, section, option, value) :

def set(self, section, option, value):
    raise SyntaxError("No modification authorized")

Phase 2 : Block Members

This part is a bit more problematic : in order to control the setter on a constant member, we have to disguise a method as a member using the @property decorator. The @constant decorator is simply a modified @property decorator :

# Constant decorator
def constant(f):
    def fset(self, value):
        raise SyntaxError("Don't touch that !")
    def fget(self):
        return f(self)
    return property(fget, fset)

# Config Class. Notice the object name in the type of class FixedConfig has to derived from
# ( Python 2.xx and new-style class purpose) 
# (see more here : https://stackoverflow.com/questions/598077/why-does-foo-setter-in-python-not-work-for-me )

class FixedConfig( object, ConfigParser):
    def __init__(self):
        ConfigParser.__init__()
        self.read("filepath to config file")

    def set(self, section, option, value):
        raise SyntaxError("No modification authorized")

    #fake DNS service : map domain names to IP
    @constant
    def DNS(self):
        return { self.get("domain names", IP) : IP  \ 
                  for IP in self.options("domain names") )

Phase 3 : Block Methods

Finally, you have to prevent class methods from be rewritten ( the magic of Python's monkey patching ). Those kind of modification are not usual, but can happen (especially when dealing with dependency inversion). In our case, we don't want FixedConfig.set to be rewritten :

config = FixedConfig()
print config.get("domain names", "127.0.0.1")
#>> 'localhost'
config.set = super(FixedConfig,self).set  # swap FixedConfig.set with ConfigParser.set
config.set("domain names", "127.0.0.1", "CommandAndControl") 
print config.get("domain names", "127.0.0.1")
#>> 'CommandAndControl'

To prevent it, you just have to decorate the set method with @constant.


Again, it does not stop a malicious person from rewritten the constant decorator and override the set property ( I don't thnink we can have this kind of protection in Python anyway) but still is much easier to track the call to the constant decorator rather than the calls to a config member throughout your project.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top