refactoring ifo.config devel
authorSandro Knauß <knauss@netzguerilla.net>
Sat, 25 Feb 2012 16:12:07 +0100
branchdevel
changeset 186 b381eaa774ab
parent 185 8ad6c097bc5b
child 187 352527f2b6ca
refactoring ifo.config
iro/config.py
iro/model/offer.py
iro/offer/provider.py
iro/offer/smstrade.py
iro/offer/smtp.py
tests/config.py
tests/job.py
tests/offer.py
tests/smstrade.py
tests/smtp.py
tests/task.py
--- a/iro/config.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/iro/config.py	Sat Feb 25 16:12:07 2012 +0100
@@ -1,11 +1,11 @@
-from ConfigParser import ConfigParser, NoOptionError
+from ConfigParser import ConfigParser
 import signal
 from functools import partial
 
 from validate import vInteger
-from error import ValidateException
+from error import NeededOption 
 
-class Config(ConfigParser):
+class MyConfigParser(ConfigParser):
     def __init__(self):
         ConfigParser.__init__(self)
         self.reloadList=[]
@@ -15,16 +15,9 @@
         ConfigParser.read(self, files)
         for s in self.sections():
             if s == "main":
-                opts=main
-                for o in opts:
-                    try:
-                        opts[o].validate(self.get(s,o),o)
-                    except (ValidateException, NoOptionError):
-                        if opts[o].must:
-                            raise
+                main.validate(self.items(s))
             else:
                 getProvider("tmp", self.get(s,'typ'), self.items(s))
-           
 
     def reload_(self):
         for f in self.reloadList:
@@ -41,9 +34,54 @@
         self.must = must
         self.default = default
 
+class Config():
+    def __init__(self, name):
+        self.name = name
+        self.options={
+            "hostname":Option(lambda x,y:x,long="Hostname under that twisted is running",must=True),
+            "port":Option(partial(vInteger,minv=0),long="Port under that twisted is running",must=True),
+            "dburl":Option(lambda x,y:x,long="Connection URL to database",must=True),
+        }
+        self.read=False
+
+
+    def _read(self, cfg, write=False):
+        c = dict(cfg)
+        for o in self.options:
+            option = self.options[o]
+            try:
+                value = option.validate(c[o],o)
+                if write:
+                    self.read = True
+                    setattr(self,o,value)
+            except KeyError:
+                if option.must:
+                    raise NeededOption(self.name, o)
+                elif write and option.default is not None:
+                    setattr(self, o, option.default)
+
+    def validate(self, cfg):
+        self._read(cfg, False)
+
+    def load(self, cfg):
+        self._read(cfg, True)
+
+    def same(self, other):
+        for o in self.options:
+            if getattr(self,o) != getattr(other,o):
+                return False
+        else:
+            return True
+
 def readConfig():
-    config.read(confFiles)
-    config.reload()
+    configParser.read(confFiles)
+    configParser.reload()
+    if not main.read:
+        main.load(configParser.items("main"))
+    else:
+        m = Config("main").load(configParser.items("main"))
+        if not main.same(m):
+            raise Exception("Main options can't be reloaded, you have to restart.")
 
 def registerSignal():
     '''register readConfig to SIGUSR2'''
@@ -52,8 +90,7 @@
 
     signal.signal(signal.SIGUSR2,rC)
 
-config=Config()
+configParser = MyConfigParser()
 confFiles=["iro.conf", "~/iro.conf","/etc/iro/iro.conf"]
-main={"hostname":Option(lambda x,y:x,long="Hostname under that twisted is running",must=True),
-        "port":Option(partial(vInteger,minv=0),long="Port under that twisted is running",must=True),
-        }
+
+main = Config("main")
--- a/iro/model/offer.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/iro/model/offer.py	Sat Feb 25 16:12:07 2012 +0100
@@ -1,7 +1,7 @@
 from .dbdefer import dbdefer
 
 import schema
-from ..config import config
+from ..config import configParser
 from ..offer import getProvider, Offer
 
 @dbdefer
@@ -22,8 +22,8 @@
 def loadOffers(session):
     offers.clear()
     providers.clear()
-    for provider in ( s for s in config.sections() if not s in ["main",]):
-        p=getProvider(provider,config.get(provider,"typ"),config.items(provider))
+    for provider in ( s for s in configParser.sections() if not s in ["main",]):
+        p=getProvider(provider,configParser.get(provider,"typ"),configParser.items(provider))
         for t in p.typs:
             for r in p.typs[t]:
                 n = schema.Offer.get(session, provider, r, t).name
@@ -33,5 +33,5 @@
 offers={}
 providers={}
 
-config.registerReload(loadOffers)
+configParser.registerReload(loadOffers)
 
--- a/iro/offer/provider.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/iro/offer/provider.py	Sat Feb 25 16:12:07 2012 +0100
@@ -1,35 +1,18 @@
 from functools import partial
 
-from ..error import NoRoute, NoTyp, ValidateException, NoProvider, NeededOption
-from ..config import Option
+from ..error import NoRoute, NoTyp, ValidateException, NoProvider
+from ..config import Option, Config
 
-class Provider():
-    def __init__(self, name, config, typs={}):
-        self.name = name
-        self.config = config
+class Provider(Config):
+    def __init__(self, name, typs={}):
+        Config.__init__(self, name)
         self.typs=typs
         self.testmode = False
-        
+
         self.options = {
                 "typ":Option(vProvider, long="One available provider typ.", must=True)
                 }
 
-    def loadConfig(self):
-        c=dict(self.config)
-        for o in self.options:
-            try:
-                value = self.options[o].validate(c[o],o)
-                setattr(self, o, value)
-            except (KeyError):
-                if self.options[o].must:
-                    raise NeededOption(self.name, o) 
-                elif self.options[o].default is not None:
-                    setattr(self,o,self.options[o].default)
-
-        for (n, v) in self.config:
-            if n == "typ":
-                self.typ = v
-
     def send(self, typ, route, recipient, message):
         pass
 
@@ -43,7 +26,9 @@
 
 def getProvider(name, typ, config):
     try:
-        return providers[typ](name,config)
+        p = providers[typ](name)
+        p.load(config)
+        return p
     except KeyError:
         raise NoProvider(typ)
 
--- a/iro/offer/smstrade.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/iro/offer/smstrade.py	Sat Feb 25 16:12:07 2012 +0100
@@ -79,13 +79,12 @@
             "count":('boolean',False),
             "cost":('boolean',False),
            }
-    def __init__(self, name, config):       
+    def __init__(self, name):       
         self.url = "https://gateway.smstrade.de"
-        Provider.__init__(self,name,config,{"sms":["basic","economy","gold","direct"]})
+        Provider.__init__(self, name, {"sms":["basic","economy","gold","direct"]})
         self.options.update({
             "key":Option(lambda x,y:x,long="smstrade Gateway Key https://login.smstrade.de/index.php?gateway", must=True)
             })
-        self.loadConfig()
 
     def send(self, route, sms, recipient):
         """send SMS with $sms to $recipients"""
--- a/iro/offer/smtp.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/iro/offer/smtp.py	Sat Feb 25 16:12:07 2012 +0100
@@ -21,8 +21,8 @@
 from .provider import Provider, providers
 
 class SMTP(Provider):
-    def __init__(self, name, config):
-        Provider.__init__(self,name,config,{"mail":[None]})
+    def __init__(self, name):
+        Provider.__init__(self,name,{"mail":[None]})
         self.options.update({
             "send_from":Option(vEmail,long="Emailaddress from which mail will be sended.",must=True),
             "host":Option(lambda x,y:x, long="Hostname of MTA", must=True),
@@ -32,7 +32,6 @@
             "TLS":Option(vBool,long="use TLS for connection to MTA", default=False),
             "SSL":Option(vBool,long="use SSL for connection to MTA", default=False),
             })
-        self.loadConfig()
 
     def send(self,mail,recipient):   
         if not self.testmode:
--- a/tests/config.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/tests/config.py	Sat Feb 25 16:12:07 2012 +0100
@@ -3,25 +3,29 @@
 import signal
 import io
 import ConfigParser
-from  iro import config 
+from  iro import config, error 
 from iro.offer.provider import Provider, providers
 
 class TestConfig(unittest.TestCase):
     '''test config class'''
     
     def setUp(self):
-        self._reloadList=config.config.reloadList
-        config.config.reloadList=[]
+        self._reloadList=config.configParser.reloadList
+        config.configParser.reloadList=[]
 
     def tearDown(self):
-        config.config.reloadList = self._reloadList
+        config.configParser.reloadList = self._reloadList
 
-    @patch('iro.config.config')
-    def testReadConfig(self,pConfig):
+    @patch('iro.config.main')
+    @patch('iro.config.configParser')
+    def testReadConfig(self,pConfig,pMain):
+        pMain.read = False
         config.readConfig()
-        self.assertEqual([i[0] for i in pConfig.method_calls],["read","reload"])
+        self.assertEqual([i[0] for i in pConfig.method_calls],["read","reload","items"])
         pConfig.read.assert_called_once_with(config.confFiles)
+        pConfig.items.assert_called_once_with("main")
         pConfig.reload.assert_called_once_with()
+        self.assertEqual(pMain.load.called,1)
 
     @patch('signal.signal')
     @patch('iro.config.readConfig')
@@ -35,93 +39,97 @@
     def testRegisterReload(self):
         def x():
             pass
-        config.config.registerReload(x)
-        self.assertEqual(config.config.reloadList,[x])
+        config.configParser.registerReload(x)
+        self.assertEqual(config.configParser.reloadList,[x])
 
     def testReload(self):
         x = Mock()
-        config.config.reloadList = [x] 
-        config.config.reload_()
+        config.configParser.reloadList = [x] 
+        config.configParser.reload_()
         x.assert_called_once_with()
 
 
 class TestRead(unittest.TestCase):
 
     def tearDown(self):
-        for s in config.config.sections():
-            config.config.remove_section(s)
+        for s in config.configParser.sections():
+            config.configParser.remove_section(s)
 
     @patch('iro.config.ConfigParser.read')
     def testMain(self,pRead):
         sample_config = """[main]
 hostname = localhost
 port = 8000
+dburl = sdfdsafgsfdg
 """
-        config.config.readfp(io.BytesIO(sample_config))
-        config.config.read([])
-        pRead.assert_called_once_with(config.config,[])
+        config.configParser.readfp(io.BytesIO(sample_config))
+        config.configParser.read([])
+        pRead.assert_called_once_with(config.configParser,[])
 
     @patch('iro.config.ConfigParser.read')
     def testMainBadPort(self,pRead):
         sample_config = """[main]
 hostname = localhost
 port = -8000
+dburl = sadfaserasg
 """
-        config.config.readfp(io.BytesIO(sample_config))
-        self.assertRaises(config.ValidateException, config.config.read, [])
+        config.configParser.readfp(io.BytesIO(sample_config))
+        self.assertRaises(error.ValidateException, config.configParser.read, [])
 
     @patch('iro.config.ConfigParser.read')
     def testMainNoMust(self,pRead):
         sample_config = """[main]
 port = 8000
+dburl = asdfgdsrg
 """
-        config.config.readfp(io.BytesIO(sample_config))
-        self.assertRaises(ConfigParser.NoOptionError, config.config.read, [])
+        config.configParser.readfp(io.BytesIO(sample_config))
+        self.assertRaises(config.NeededOption, config.configParser.read, [])
 
     @patch('iro.config.ConfigParser.read')
     def testMust(self,pRead):
         v=Mock()
-        config.main["test"] = config.Option(v)
+        config.main.options["test"] = config.Option(v)
         try:
             sample_config = """[main]
 hostname = localhost
+dburl = sdfawersdf
 port = 8000
 """
-            config.config.readfp(io.BytesIO(sample_config))
-            config.config.read([])
+            config.configParser.readfp(io.BytesIO(sample_config))
+            config.configParser.read([])
             self.assertEqual(v.called,0)
             sample_config = """[main]
 hostname = localhost
+dburl = adfgsdftsfg
 port = 8000
 test = foohu
     """
-            config.config.readfp(io.BytesIO(sample_config))
-            config.config.read([])
+            config.configParser.readfp(io.BytesIO(sample_config))
+            config.configParser.read([])
             v.assert_called_once_with("foohu","test")
         finally:
-            del(config.main["test"])
+            del(config.main.options["test"])
 
     @patch('iro.config.ConfigParser.read')
     def testProviders(self, pRead):
         v=Mock()
         class TestProvider(Provider):
-            def __init__(self,name,c):
-                Provider.__init__(self,name,c)
+            def __init__(self,name):
+                Provider.__init__(self,name)
                 self.options.update({"test":config.Option(v)})
-                self.loadConfig()
         providers["test"]=TestProvider
         try:
             sample_config = """[p]
 """
-            config.config.readfp(io.BytesIO(sample_config))
-            self.assertRaises(ConfigParser.NoOptionError, config.config.read, [])  
+            config.configParser.readfp(io.BytesIO(sample_config))
+            self.assertRaises(ConfigParser.NoOptionError, config.configParser.read, [])  
             self.assertEqual(v.called,0)
             sample_config = """[p]
 typ= test
 test= foo
 """
-            config.config.readfp(io.BytesIO(sample_config))
-            config.config.read([])
+            config.configParser.readfp(io.BytesIO(sample_config))
+            config.configParser.read([])
             v.assert_called_once_with("foo","test")
         finally:
             del(providers["test"])
--- a/tests/job.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/tests/job.py	Sat Feb 25 16:12:07 2012 +0100
@@ -126,7 +126,7 @@
         self.user = u
         self.offer = o
         
-        self.provider=Provider("bla", [], {"sms":["a","b","c"]})
+        self.provider=Provider("bla", {"sms":["a","b","c"]})
         self.job = exJobs.create(u, [Telnumber('123456789')], SMS('test'), [])
 
     def tearDown(self):
--- a/tests/offer.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/tests/offer.py	Sat Feb 25 16:12:07 2012 +0100
@@ -4,7 +4,7 @@
 import io
 
 from iro.model import offer
-from iro.config import config
+from iro.config import configParser
 from iro.offer import Offer, providers as OfferProviders, Provider
 from iro.model.schema import User, Offer as DBOffer, Userright
 from iro.controller.pool  import dbPool
@@ -18,8 +18,8 @@
         dbPool.start(reactor)
 
     def tearDown(self):
-        for s in config.sections():
-            config.remove_section(s)
+        for s in configParser.sections():
+            configParser.remove_section(s)
         
         dbPool.pool.stop()
         offer.offers.clear()
@@ -34,7 +34,7 @@
 
     def testReloadList(self):
         '''test if loadOffers will be fired by reloading Config'''
-        self.assertTrue(offer.loadOffers in config.reloadList)
+        self.assertTrue(offer.loadOffers in configParser.reloadList)
 
     @inlineCallbacks
     def testExtendProviderUnknown(self):
@@ -72,7 +72,7 @@
             o=DBOffer(name="oh", provider="bla", route="a", typ="sms")
             u.rights.append(Userright(o)) 
         
-        offer.providers={"bla":Provider("bla", [], {"sms":["a","b","c"]})}
+        offer.providers={"bla":Provider("bla", {"sms":["a","b","c"]})}
 
         for l in [['bla'],['oh'],['oh','bla'],['bla','oh']]:
             ret = yield offer.extendProvider(u, "sms", l)
@@ -89,7 +89,7 @@
             o=DBOffer(name="a", provider="bla", route="b", typ="sms")
             u.rights.append(Userright(o)) 
         
-        offer.providers={"bla":Provider("bla", [], {"sms":["a","b","c"]})}
+        offer.providers={"bla":Provider("bla",  {"sms":["a","b","c"]})}
 
         ret = yield offer.extendProvider(u, "sms",  ["bla"])
         self.assertEqual(ret, ["oh","a"])
@@ -104,9 +104,8 @@
     def testLoadOffers(self):
         
         class TestProvider(Provider):
-            def __init__(self,name,config):
-                Provider.__init__(self,name,config,{"sms":["a",]})
-                self.loadConfig()
+            def __init__(self,name):
+                Provider.__init__(self,name,{"sms":["a",]})
         
         with self.session() as session:
             session.add(DBOffer(name="oh", provider="p", route="a", typ="sms"))
@@ -114,7 +113,7 @@
         sample_config = """[p]
 typ = test
 """
-        config.readfp(io.BytesIO(sample_config))
+        configParser.readfp(io.BytesIO(sample_config))
         OfferProviders["test"]=TestProvider
         yield offer.loadOffers()        
         self.assertEqual(offer.offers.keys(),["oh"])
@@ -130,7 +129,7 @@
         sample_config = """[p]
 typ = unknown
 """
-        config.readfp(io.BytesIO(sample_config))
+        configParser.readfp(io.BytesIO(sample_config))
         d = offer.loadOffers()        
         self.assertFailure(d, NoProvider)
         return d
--- a/tests/smstrade.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/tests/smstrade.py	Sat Feb 25 16:12:07 2012 +0100
@@ -13,14 +13,16 @@
 class TestSMStradeProvider(unittest.TestCase):
 
     def getProvider(self, c=None):
-        ret={"key":"XXXXXX",
+        _c={"key":"XXXXXXXX",
             "typ":"smstrade",
             }
 
         if c:
-            ret.update(c)
+            _c.update(c)
 
-        return Smstrade("test",ret.items())
+        ret = Smstrade("test")
+        ret.load(_c.items())
+        return ret
 
     @patch("urllib.urlopen")
     def testSendSMS(self,mock_urlopen):
@@ -28,7 +30,7 @@
         f.readlines.return_value = ["100","12345678","0.055","1"]
         mock_urlopen.return_value = f
 
-        params = ["key=XXXXXX","to=00491701234567", "message=Hello+World", "route=gold", "message_id=1", "cost=1","count=1",'charset=utf-8']
+        params = ["key=XXXXXXXX","to=00491701234567", "message=Hello+World", "route=gold", "message_id=1", "cost=1","count=1",'charset=utf-8']
         params.sort()
         
         p=self.getProvider()
@@ -49,11 +51,10 @@
     testStatusCode.todo = "to implement"
 
     def testNeededOption(self):
-        c={"key":"XXXXXXXX","typ":"smstrade"}
-        s=Smstrade("test",c.items())
+        s= self.getProvider()
         self.assertEqual(s.key, "XXXXXXXX")
 
-        self.assertRaises(NeededOption,Smstrade,"test",[])
+        self.assertRaises(NeededOption, s.load,[])
 
     def testSendFunc(self):
         s = self.getProvider()
--- a/tests/smtp.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/tests/smtp.py	Sat Feb 25 16:12:07 2012 +0100
@@ -24,16 +24,18 @@
         self.smtp_server.close()
 
     def getSMTP(self, c=None):
-        ret={"send_from":"send@t.de",
+        _c={"send_from":"send@t.de",
             "host":HOST,
             "port":PORT,
             "typ":"smtp",
             }
 
         if c:
-            ret.update(c)
+            _c.update(c)
 
-        return SMTP("test",ret.items())
+        ret = SMTP("test")
+        ret.load(_c.items())
+        return ret
 
     def testSendMail(self):
         p=self.getSMTP()
@@ -120,7 +122,7 @@
             "password":"p",
             "typ":"smtp",
             }
-        s=SMTP("test",c.items())
+        s = self.getSMTP(c)
         self.assertEqual(s.send_from, "send@t.de")
         self.assertEqual(s.host, HOST)
         self.assertEqual(s.port, PORT)
@@ -130,12 +132,12 @@
         self.assertEqual(s.TLS,False)
 
         c.update({"TLS":True, "SSL":True})
-        s=SMTP("test", c.items())
+        s = self.getSMTP(c)
         self.assertEqual(s.SSL,True)
         self.assertEqual(s.TLS,True)
         
         del c["host"]
-        self.assertRaises(NeededOption,SMTP,"test",c.items())
+        self.assertRaises(NeededOption, s.load, c)
 
     def testSendFunc(self):
         s = self.getSMTP()
--- a/tests/task.py	Thu Feb 23 16:59:49 2012 +0100
+++ b/tests/task.py	Sat Feb 25 16:12:07 2012 +0100
@@ -54,7 +54,7 @@
             o=DBOffer(name="test", provider="bla", route="basic", typ="sms")
             u.rights.append(Userright(o)) 
         
-        p=Provider(name="p", config={}, typs={"sms":["test",]})
+        p=Provider(name="p", typs={"sms":["test",]})
         def send(typ,route,recipient,message):
             return Status(provider=p, route=route)
         p.send=send