Skip to content

Commit 091a3ec

Browse files
committed
Support filtering DSN by scope
The `pyodbc.dataSources()` function now accepts an optional keyword argument ("scope") to filter the reported DSNs to just the user DSNs or just the system DSNs. Closes #1415
1 parent cfe0575 commit 091a3ec

2 files changed

Lines changed: 35 additions & 6 deletions

File tree

src/pyodbc.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,10 +945,13 @@ class Row:
945945

946946
# module functions
947947

948-
def dataSources() -> dict[str, str]:
948+
def dataSources(*, scope: str | None = None) -> dict[str, str]:
949949
"""Return all available Data Source Names (DSNs), typically from the odbcinst.ini file
950950
or the Windows ODBC Data Source Administrator.
951951
952+
Args:
953+
scope: optional filter ("user" or "system") to control which DSNs are returned.
954+
952955
Returns:
953956
A dictionary of DSNs and their textual descriptions.
954957
"""

src/pyodbcmodule.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,30 @@ static PyObject* mod_drivers(PyObject* self)
574574
}
575575

576576

577-
static PyObject* mod_datasources(PyObject* self)
577+
static PyObject* mod_datasources(PyObject* self, PyObject* args, PyObject* kwargs)
578578
{
579579
UNUSED(self);
580580

581+
static char* kwlist[] = { "scope", NULL };
582+
const char* scope = NULL;
583+
584+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$s", kwlist, &scope))
585+
return 0;
586+
587+
SQLUSMALLINT nDirectionFirst;
588+
589+
if (scope == NULL)
590+
nDirectionFirst = SQL_FETCH_FIRST;
591+
else if (strcmp(scope, "user") == 0)
592+
nDirectionFirst = SQL_FETCH_FIRST_USER;
593+
else if (strcmp(scope, "system") == 0)
594+
nDirectionFirst = SQL_FETCH_FIRST_SYSTEM;
595+
else
596+
{
597+
PyErr_SetString(PyExc_ValueError, "scope must be 'user' or 'system'");
598+
return 0;
599+
}
600+
581601
if (henv == SQL_NULL_HANDLE && !AllocateEnv())
582602
return 0;
583603

@@ -597,7 +617,7 @@ static PyObject* mod_datasources(PyObject* self)
597617
SWORD cbDSN;
598618
SWORD cbDesc;
599619

600-
SQLUSMALLINT nDirection = SQL_FETCH_FIRST;
620+
SQLUSMALLINT nDirection = nDirectionFirst;
601621

602622
SQLRETURN ret;
603623

@@ -768,9 +788,15 @@ static char drivers_doc[] =
768788
"Returns a list of installed drivers.";
769789

770790
static char datasources_doc[] =
771-
"dataSources() --> { DSN : Description }\n" \
791+
"dataSources(*, scope=None) --> { DSN : Description }\n" \
792+
"\n" \
793+
"Returns a dictionary mapping available DSNs to their descriptions.\n" \
772794
"\n" \
773-
"Returns a dictionary mapping available DSNs to their descriptions.";
795+
"scope\n" \
796+
" An optional keyword-only argument to filter the returned DSNs.\n" \
797+
" If set to 'user', only user DSNs are returned.\n" \
798+
" If set to 'system', only system DSNs are returned.\n" \
799+
" If not set, all DSNs are returned.";
774800

775801
static char setdecimalsep_doc[] =
776802
"setDecimalSeparator(string) -> None\n" \
@@ -792,7 +818,7 @@ static PyMethodDef pyodbc_methods[] =
792818
{ "getDecimalSeparator", (PyCFunction)mod_getdecimalsep, METH_NOARGS, getdecimalsep_doc },
793819
{ "TimestampFromTicks", (PyCFunction)mod_timestampfromticks, METH_VARARGS, timestampfromticks_doc },
794820
{ "drivers", (PyCFunction)mod_drivers, METH_NOARGS, drivers_doc },
795-
{ "dataSources", (PyCFunction)mod_datasources, METH_NOARGS, datasources_doc },
821+
{ "dataSources", (PyCFunction)mod_datasources, METH_VARARGS|METH_KEYWORDS, datasources_doc },
796822
{ 0, 0, 0, 0 }
797823
};
798824

0 commit comments

Comments
 (0)