Repository: adamchainz/django-mysql

Issue:
Singleton global/session status objects
It's a bit undjango to have to instantiate a class to do a simple lookup of status. It would be more natural to have a dict like the connection wrapper for getting the status, with singleton lazy wrapper for each type for your main DB connection.

```
from django_mysql.status import global_status
global_status.dict()
```



Discussion:

Resolving patch:
diff --git a/django_mysql/status.py b/django_mysql/status.py
--- a/django_mysql/status.py
+++ b/django_mysql/status.py
@@ -6,6 +6,7 @@
 
 from django.db import connections
 from django.db.utils import DEFAULT_DB_ALIAS
+from django.utils.functional import SimpleLazyObject
 
 from django_mysql.exceptions import TimeoutError
 
@@ -116,3 +117,7 @@ def wait_until_load_low(self, thresholds=None, timeout=60.0, sleep=0.1):
 
 class SessionStatus(BaseStatus):
     query = "SHOW SESSION STATUS"
+
+
+global_status = SimpleLazyObject(GlobalStatus)
+session_status = SimpleLazyObject(SessionStatus)


Test patch:
diff --git a/tests/django_mysql_tests/test_status.py b/tests/django_mysql_tests/test_status.py
--- a/tests/django_mysql_tests/test_status.py
+++ b/tests/django_mysql_tests/test_status.py
@@ -2,35 +2,34 @@
 from django.test import TestCase
 
 from django_mysql.exceptions import TimeoutError
-from django_mysql.status import GlobalStatus, SessionStatus
+from django_mysql.status import (
+    global_status, GlobalStatus, session_status, SessionStatus
+)
 
 
 class GlobalStatusTests(TestCase):
 
     def test_get(self):
-        status = GlobalStatus()
-        running = status.get('Threads_running')
+        running = global_status.get('Threads_running')
         self.assertTrue(isinstance(running, int))
         self.assertGreaterEqual(running, 1)
 
-        cost = status.get('Last_query_cost')
+        cost = global_status.get('Last_query_cost')
         self.assertTrue(isinstance(cost, float))
         self.assertGreaterEqual(cost, 0.00)
 
         with self.assertRaises(ValueError) as cm:
-            status.get('foo%')
+            global_status.get('foo%')
         self.assertIn('wildcards', str(cm.exception))
 
         with self.assertRaises(KeyError):
-            status.get('Does_not_exist')
+            global_status.get('Does_not_exist')
 
     def test_get_many(self):
-        status = GlobalStatus()
-
-        myvars = status.get_many([])
+        myvars = global_status.get_many([])
         self.assertEqual(myvars, {})
 
-        myvars = status.get_many(['Threads_running', 'Uptime'])
+        myvars = global_status.get_many(['Threads_running', 'Uptime'])
         self.assertTrue(isinstance(myvars, dict))
         self.assertIn('Threads_running', myvars)
         self.assertTrue(isinstance(myvars['Threads_running'], int))
@@ -38,12 +37,11 @@ def test_get_many(self):
         self.assertTrue(isinstance(myvars['Uptime'], int))
 
         with self.assertRaises(ValueError) as cm:
-            status.get_many(['foo%'])
+            global_status.get_many(['foo%'])
         self.assertIn('wildcards', str(cm.exception))
 
     def test_as_dict(self):
-        status = GlobalStatus()
-        status_dict = status.as_dict()
+        status_dict = global_status.as_dict()
 
         self.assertIn('Aborted_clients', status_dict)  # Global-only variable
 
@@ -56,27 +54,24 @@ def test_as_dict(self):
         self.assertTrue(isinstance(status_dict['Compression'], bool))
 
     def test_as_dict_prefix(self):
-        status = GlobalStatus()
-        status_dict = status.as_dict()
+        status_dict = global_status.as_dict()
 
-        status_dict_threads = status.as_dict('Threads_')
+        status_dict_threads = global_status.as_dict('Threads_')
         self.assertLess(len(status_dict_threads), len(status_dict))
         for key in status_dict_threads:
             self.assertTrue(key.startswith('Threads_'))
 
-        status_dict_foo = status.as_dict('Foo_Non_Existent')
+        status_dict_foo = global_status.as_dict('Foo_Non_Existent')
         self.assertEqual(len(status_dict_foo), 0)
 
     def test_wait_until_load_low(self):
-        status = GlobalStatus()
-
         # Assume tests are running on a non-busy server
-        status.wait_until_load_low()
-        status.wait_until_load_low({'Threads_running': 50,
-                                    'Threads_connected': 100})
+        global_status.wait_until_load_low()
+        global_status.wait_until_load_low({'Threads_running': 50,
+                                           'Threads_connected': 100})
 
         with self.assertRaises(TimeoutError) as cm:
-            status.wait_until_load_low(
+            global_status.wait_until_load_low(
                 {'Threads_running': -1},  # obviously impossible
                 timeout=0.001,
                 sleep=0.0005
@@ -86,7 +81,7 @@ def test_wait_until_load_low(self):
         self.assertIn('-1', message)
 
         with self.assertRaises(TimeoutError) as cm:
-            status.wait_until_load_low(
+            global_status.wait_until_load_low(
                 {'Threads_running': 1000000,
                  'Uptime': -1},  # obviously impossible
                 timeout=0.001,
@@ -109,31 +104,34 @@ def test_other_databases(self):
 class SessionStatusTests(TestCase):
 
     def test_get(self):
-        status = SessionStatus()
-
-        bytes_received = status.get('Bytes_received')
+        bytes_received = session_status.get('Bytes_received')
         self.assertTrue(isinstance(bytes_received, int))
         self.assertGreaterEqual(bytes_received, 0)
 
-        bytes_received_2 = status.get('Bytes_received')
+        bytes_received_2 = session_status.get('Bytes_received')
         self.assertGreaterEqual(bytes_received_2, bytes_received)
 
-        cost = status.get('Last_query_cost')
+        cost = session_status.get('Last_query_cost')
         self.assertTrue(isinstance(cost, float))
         self.assertGreaterEqual(cost, 0.00)
 
         with self.assertRaises(ValueError) as cm:
-            status.get('foo%')
+            session_status.get('foo%')
         self.assertIn('wildcards', str(cm.exception))
 
         with self.assertRaises(KeyError):
-            status.get('Does_not_exist')
+            session_status.get('Does_not_exist')
 
     def test_as_dict(self):
-        status = SessionStatus()
-        status_dict = status.as_dict()
+        status_dict = session_status.as_dict()
 
         self.assertIn('Compression', status_dict)
 
         self.assertTrue(isinstance(status_dict['Threads_running'], int))
         self.assertGreaterEqual(status_dict['Threads_running'], 1)
+
+    def test_other_databases(self):
+        status = SessionStatus(using='secondary')
+        running = status.get('Threads_running')
+        self.assertTrue(isinstance(running, int))
+        self.assertGreaterEqual(running, 1)