Skip to content
This repository
Browse code

Added pyodbc.drivers() for Windows builds.

In the future, I will try to add the method to other platforms by reading the iODBC and
unixODBC configuration files.
  • Loading branch information...
commit eeede2f020396bab69cf31ed767097bb9ef5cc20 1 parent 9dd144f
Michael Kleehammer authored
1  setup.py
@@ -110,6 +110,7 @@ def get_compiler_settings(version_str):
110 110
111 111 if os.name == 'nt':
112 112 settings['libraries'].append('odbc32')
  113 + settings['libraries'].append('advapi32')
113 114
114 115 elif os.environ.get("OS", '').lower().startswith('windows'):
115 116 # Windows Cygwin (posix on windows)
42 src/pyodbcmodule.cpp
@@ -579,6 +579,44 @@ static PyObject* mod_leakcheck(PyObject* self, PyObject* args)
579 579 }
580 580 #endif
581 581
  582 +#ifdef WINVER
  583 +static char drivers_doc[] = "drivers() -> [ driver, ... ]\n\nReturns a list of installed drivers";
  584 +
  585 +static PyObject* mod_drivers(PyObject* self, PyObject* args)
  586 +{
  587 + UNUSED(self, args);
  588 +
  589 + RegKey key;
  590 + long ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\ODBC\\ODBCINST.INI\\ODBC Drivers", 0, KEY_QUERY_VALUE, &key.hkey);
  591 + if (ret != ERROR_SUCCESS)
  592 + return PyErr_Format(PyExc_RuntimeError, "Unable to access the driver list in the registry. error=%ld", ret);
  593 +
  594 + Object results(PyList_New(0));
  595 + DWORD index = 0;
  596 + char name[255];
  597 + DWORD length = _countof(name);
  598 +
  599 + while (RegEnumValue(key, index++, name, &length, 0, 0, 0, 0) == ERROR_SUCCESS)
  600 + {
  601 + if (ret != ERROR_SUCCESS)
  602 + return PyErr_Format(PyExc_RuntimeError, "RegEnumKeyEx failed with error %ld\n", ret);
  603 +
  604 + PyObject* oname = PyString_FromStringAndSize(name, length);
  605 + if (!oname)
  606 + return 0;
  607 +
  608 + if (PyList_Append(results.Get(), oname) != 0)
  609 + {
  610 + Py_DECREF(oname);
  611 + return 0;
  612 + }
  613 + length = _countof(name);
  614 + }
  615 +
  616 + return results.Detach();
  617 +}
  618 +#endif
  619 +
582 620 static PyMethodDef pyodbc_methods[] =
583 621 {
584 622 { "connect", (PyCFunction)mod_connect, METH_VARARGS|METH_KEYWORDS, connect_doc },
@@ -587,6 +625,10 @@ static PyMethodDef pyodbc_methods[] =
587 625 { "TimestampFromTicks", (PyCFunction)mod_timestampfromticks, METH_VARARGS, timestampfromticks_doc },
588 626 { "dataSources", (PyCFunction)mod_datasources, METH_NOARGS, datasources_doc },
589 627
  628 +#ifdef WINVER
  629 + { "drivers", (PyCFunction)mod_drivers, METH_NOARGS, drivers_doc },
  630 +#endif
  631 +
590 632 #ifdef PYODBC_LEAK_CHECK
591 633 { "leakcheck", (PyCFunction)mod_leakcheck, METH_NOARGS, 0 },
592 634 #endif
21 src/wrapper.h
@@ -55,4 +55,25 @@ class Object
55 55 }
56 56 };
57 57
  58 +
  59 +#ifdef WINVER
  60 +struct RegKey
  61 +{
  62 + HKEY hkey;
  63 +
  64 + RegKey()
  65 + {
  66 + hkey = 0;
  67 + }
  68 +
  69 + ~RegKey()
  70 + {
  71 + if (hkey != 0)
  72 + RegCloseKey(hkey);
  73 + }
  74 +
  75 + operator HKEY() { return hkey; }
  76 +};
  77 +#endif
  78 +
58 79 #endif // _WRAPPER_H_
10 tests/sqlservertests.py
@@ -1229,6 +1229,16 @@ def test_no_fetch(self):
1229 1229 self.cursor.execute('select 1')
1230 1230 self.cursor.execute('select 1')
1231 1231
  1232 + def test_drivers(self):
  1233 + drivers = pyodbc.drivers()
  1234 + self.assertEqual(list, type(drivers))
  1235 + self.assert_(len(drivers) > 1)
  1236 +
  1237 + m = re.search('DRIVER={([^}]+)}', self.connection_string, re.IGNORECASE)
  1238 + current = m.group(1)
  1239 + self.assert_(current in drivers)
  1240 +
  1241 +
1232 1242
1233 1243 def main():
1234 1244 from optparse import OptionParser

0 comments on commit eeede2f

Please sign in to comment.
Something went wrong with that request. Please try again.