Changeset: 43cb06902e1f for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=43cb06902e1f
Added Files:
        clients/python/monetdb/control.py
        clients/python/test/control.py
Modified Files:
        clients/python/monetdb/mapi.py
Branch: default
Log Message:

we can now manage monetdb databases from python.


diffs (222 lines):

diff --git a/clients/python/monetdb/control.py 
b/clients/python/monetdb/control.py
new file mode 100644
--- /dev/null
+++ b/clients/python/monetdb/control.py
@@ -0,0 +1,54 @@
+
+from monetdb import mapi
+
+class Control:
+    def __init__(self, hostname, port, passphrase):
+        self.server = mapi.Server()
+        self.server.connect(hostname, port, 'monetdb', passphrase, 
'merovingian', 'control')
+
+    def _send_command(self, database_name, command, has_output=False):
+        return self.server.cmd("%s %s\n" % (database_name, command))
+
+    def create(self, database_name):
+        return self._send_command(database_name, "create")
+
+    def destroy(self, database_name):
+        return self._send_command(database_name, "destroy")
+
+    def lock(self, database_name):
+        return self._send_command(database_name, "lock")
+
+    def release(self, database_name):
+        return self._send_command(database_name, "release")
+
+    def status(self, database_name):
+        return self._send_command(database_name, "status", True)
+
+    def start(self, database_name):
+        return self._send_command(database_name, "start")
+
+    def stop(self, database_name):
+        return self._send_command(database_name, "stop")
+
+    def kill(self, database_name):
+        return self._send_command(database_name, "kill")
+
+    def set(self, database_name, property_, value):
+        return self._send_command(database_name, "%s=%s" % (property_, value))
+
+    def get(self, database_name):
+        properties = self._send_command(database_name, "get")
+        values = {}
+        for dirty_line in properties.split("\n")[1:]:
+            line = dirty_line[1:]
+            if not line.startswith("#"):
+                if "=" in line:
+                    split = line.split("=")
+                    values[split[0]] = split[1]
+        return values
+
+    def inherit(self, database_name, property_):
+        return self._send_command(database_name, property_ + "=")
+
+    def version(self, database_name):
+        self._send_command(database_name, "version")
\ No newline at end of file
diff --git a/clients/python/monetdb/mapi.py b/clients/python/monetdb/mapi.py
--- a/clients/python/monetdb/mapi.py
+++ b/clients/python/monetdb/mapi.py
@@ -24,6 +24,7 @@ import logging
 import struct
 import hashlib
 from cStringIO import StringIO
+import time
 
 from monetdb.exceptions import OperationalError, DatabaseError, 
ProgrammingError, NotSupportedError
 
@@ -45,6 +46,7 @@ MSG_QBLOCK = "&6"
 MSG_HEADER = "%"
 MSG_TUPLE = "["
 MSG_REDIRECT = "^"
+MSG_OK = "=OK"
 
 STATE_INIT = 0
 STATE_READY = 1
@@ -100,9 +102,12 @@ class Server(object):
         self.__putblock(response)
         prompt = self.__getblock().strip()
 
-        if len(prompt) == 0:
+        if len(prompt) == 0 :
             # Empty response, server is happy
             pass
+        elif prompt == MSG_OK:
+            # New behaviour, I think it is something good
+            pass
         elif prompt.startswith(MSG_INFO):
             logger.info("II %s" % prompt[1:])
 
@@ -134,11 +139,9 @@ class Server(object):
                         self.password, self.database, self.language)
 
             else:
-                logger.error('!' + prompt[0])
                 raise ProgrammingError("unknown redirect: %s" % prompt)
 
         else:
-            logger.error('!' + prompt[0])
             raise ProgrammingError("unknown state: %s" % prompt)
 
         self.state = STATE_READY
@@ -161,7 +164,10 @@ class Server(object):
         self.__putblock(operation)
         response = self.__getblock()
         if not len(response):
-            return
+            return True
+        elif response.startswith(MSG_OK):
+            # New behaviour, I think it is something good
+            return response.strip()
         if response == MSG_MORE:
             # tell server it isn't going to get more
             return self.cmd("")
@@ -233,6 +239,8 @@ class Server(object):
         while count > 0:
             try:
                 recv = self.socket.recv(bytes)
+                if len(recv) == 0:
+                    time.sleep(1)
                 logger.debug("II: package size: %i payload: %s" % (len(recv), 
recv))
             except socket.error, error:
                 raise OperationalError(error[1])
diff --git a/clients/python/test/control.py b/clients/python/test/control.py
new file mode 100644
--- /dev/null
+++ b/clients/python/test/control.py
@@ -0,0 +1,90 @@
+import unittest
+from monetdb.control import Control
+from monetdb.exceptions import OperationalError
+import logging
+logging.basicConfig(level=logging.DEBUG)
+
+database_prefix = 'controltest_'
+database_name = database_prefix + 'other'
+passphrase = 'testdb'
+
+def do_without_fail(function):
+    try:
+        function()
+    except OperationalError:
+        pass
+
+class TestManage(unittest.TestCase):
+    def setUp(self):
+        self.control = Control('localhost', 50000, passphrase)
+        do_without_fail(lambda: self.control.stop(database_name))
+        do_without_fail(lambda: self.control.destroy(database_name))
+        self.control.create(database_name)
+
+    def tearDown(self):
+        do_without_fail(lambda: self.control.stop(database_name))
+        do_without_fail(lambda: self.control.destroy(database_name))
+
+    def testCreate(self):
+        create_name = database_prefix + "create"
+        do_without_fail(lambda: self.control.destroy(create_name))
+
+        self.control.create(create_name)
+        # can't create it again
+        self.assertRaises(OperationalError, self.control.create, create_name)
+
+        # cleanup
+        do_without_fail(lambda: self.control.destroy(create_name))
+
+    def testDestroy(self):
+        destroy_name = database_prefix + "destroy"
+        self.control.create(destroy_name)
+        self.control.destroy(destroy_name)
+        self.assertRaises(OperationalError, self.control.destroy, destroy_name)
+
+    def testLock(self):
+        do_without_fail(lambda: self.control.release(database_name))
+        self.control.lock(database_name)
+        self.assertRaises(OperationalError, self.control.lock, database_name)
+
+    def testRelease(self):
+        do_without_fail(lambda: self.control.release(database_name))
+        do_without_fail(lambda: self.control.lock(database_name))
+        self.assertTrue(self.control.release(database_name))
+        self.assertRaises(OperationalError, self.control.release, 
database_name)
+
+    def testStatus(self):
+        self.control.status(database_name)
+
+    def testStart(self):
+        do_without_fail(lambda: self.control.stop(database_name))
+        self.assertTrue(self.control.start(database_name))
+
+    def testStop(self):
+        do_without_fail(lambda: self.control.start(database_name))
+        self.assertTrue(self.control.stop(database_name))
+
+    def testKill(self):
+        do_without_fail(lambda: self.control.start(database_name))
+        self.assertTrue(self.control.kill(database_name))
+
+    def testSet(self):
+        property_ = "readonly"
+        value = "yes"
+        self.control.set(database_name, property_, value)
+        properties = self.control.get(database_name)
+        self.assertEqual(properties[property_], value)
+
+    def testGet(self):
+        properties = self.control.get(database_name)
+
+    def testInherit(self):
+        self.control.set(database_name, "readonly", "yes")
+        self.assertTrue(self.control.inherit(database_name, "readonly"))
+        self.assertFalse(self.control.get(database_name).has_key("readonly"))
+
+    def testVersion(self):
+        self.control.version(database_name)
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
_______________________________________________
Checkin-list mailing list
Checkin-list@monetdb.org
http://mail.monetdb.org/mailman/listinfo/checkin-list

Reply via email to