Moving host attribute to a connection.info object

This commit is contained in:
Daniele Varrazzo 2018-10-11 22:42:52 +01:00
parent 7619c91d62
commit 0e2b516a3c
6 changed files with 193 additions and 24 deletions

View File

@ -29,6 +29,7 @@
#include "psycopg/connection.h"
#include "psycopg/cursor.h"
#include "psycopg/pqpath.h"
#include "psycopg/conninfo.h"
#include "psycopg/lobject.h"
#include "psycopg/green.h"
#include "psycopg/xid.h"
@ -992,25 +993,20 @@ psyco_conn_get_backend_pid(connectionObject *self)
return PyInt_FromLong((long)PQbackendPID(self->pgconn));
}
/* get the current host */
#define psyco_conn_host_get_doc \
"host -- Get the host name."
/* get info about the connection */
#define psyco_conn_info_get_doc \
"info -- Get connection info."
static PyObject *
psyco_conn_host_get(connectionObject *self)
psyco_conn_info_get(connectionObject *self)
{
const char *val = NULL;
EXC_IF_CONN_CLOSED(self);
val = PQhost(self->pgconn);
if (!val) {
Py_RETURN_NONE;
}
return conn_text_from_chars(self, val);
return PyObject_CallFunctionObjArgs(
(PyObject *)&connInfoType, (PyObject *)self, NULL);
}
/* reset the currect connection */
#define psyco_conn_reset_doc \
@ -1262,9 +1258,9 @@ static struct PyGetSetDef connectionObject_getsets[] = {
(getter)psyco_conn_deferrable_get,
(setter)psyco_conn_deferrable_set,
psyco_conn_deferrable_doc },
{ "host",
(getter)psyco_conn_host_get, NULL,
psyco_conn_host_get_doc },
{ "info",
(getter)psyco_conn_info_get, NULL,
psyco_conn_info_get_doc },
{NULL}
};
#undef EXCEPTION_GETTER

40
psycopg/conninfo.h Normal file
View File

@ -0,0 +1,40 @@
/* connection.h - definition for the psycopg ConnectionInfo type
*
* Copyright (C) 2018 Daniele Varrazzo <daniele.varrazzo@gmail.com>
*
* This file is part of psycopg.
*
* psycopg2 is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to link this program with the OpenSSL library (or with
* modified versions of OpenSSL that use the same license as OpenSSL),
* and distribute linked combinations including the two.
*
* You must obey the GNU Lesser General Public License in all respects for
* all of the code used other than OpenSSL.
*
* psycopg2 is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#ifndef PSYCOPG_CONNINFO_H
#define PSYCOPG_CONNINFO_H 1
#include "psycopg/connection.h"
extern HIDDEN PyTypeObject connInfoType;
typedef struct {
PyObject_HEAD
connectionObject *conn;
} connInfoObject;
#endif /* PSYCOPG_CONNINFO_H */

131
psycopg/conninfo_type.c Normal file
View File

@ -0,0 +1,131 @@
/* conninfo_type.c - present information about the libpq connection
*
* Copyright (C) 2018 Daniele Varrazzo <daniele.varrazzo@gmail.com>
*
* This file is part of psycopg.
*
* psycopg2 is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to link this program with the OpenSSL library (or with
* modified versions of OpenSSL that use the same license as OpenSSL),
* and distribute linked combinations including the two.
*
* You must obey the GNU Lesser General Public License in all respects for
* all of the code used other than OpenSSL.
*
* psycopg2 is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#define PSYCOPG_MODULE
#include "psycopg/psycopg.h"
#include "psycopg/conninfo.h"
static const char host_doc[] =
"The server host name of the active connection.";
static PyObject *
host_get(connInfoObject *self)
{
const char *val;
val = PQhost(self->conn->pgconn);
if (!val) {
Py_RETURN_NONE;
}
return conn_text_from_chars(self->conn, val);
}
static struct PyGetSetDef connInfoObject_getsets[] = {
{ "host", (getter)host_get, NULL, (char *)host_doc },
{NULL}
};
/* initialization and finalization methods */
static PyObject *
conninfo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
return type->tp_alloc(type, 0);
}
static int
conninfo_init(connInfoObject *self, PyObject *args, PyObject *kwds)
{
PyObject *conn = NULL;
if (!PyArg_ParseTuple(args, "O", &conn))
return -1;
if (!PyObject_TypeCheck(conn, &connectionType)) {
PyErr_SetString(PyExc_TypeError,
"The argument must be a psycopg2 connection");
return -1;
}
Py_INCREF(conn);
self->conn = (connectionObject *)conn;
return 0;
}
static void
conninfo_dealloc(connInfoObject* self)
{
Py_CLEAR(self->conn);
Py_TYPE(self)->tp_free((PyObject *)self);
}
/* object type */
static const char connInfoType_doc[] =
"Details of a database connection.";
PyTypeObject connInfoType = {
PyVarObject_HEAD_INIT(NULL, 0)
"psycopg2.extensions.ConnectionInfo",
sizeof(connInfoObject), 0,
(destructor)conninfo_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
connInfoType_doc, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
0, /*tp_members*/
connInfoObject_getsets, /*tp_getset*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
(initproc)conninfo_init, /*tp_init*/
0, /*tp_alloc*/
conninfo_new, /*tp_new*/
};

View File

@ -40,6 +40,7 @@
#include "psycopg/microprotocols.h"
#include "psycopg/microprotocols_proto.h"
#include "psycopg/error.h"
#include "psycopg/conninfo.h"
#include "psycopg/diagnostics.h"
#include "psycopg/adapter_qstring.h"
@ -995,6 +996,9 @@ INIT_MODULE(_psycopg)(void)
errorType.tp_base = (PyTypeObject *)PyExc_StandardError;
if (PyType_Ready(&errorType) == -1) goto exit;
Py_TYPE(&connInfoType) = &PyType_Type;
if (PyType_Ready(&connInfoType) == -1) goto exit;
Py_TYPE(&diagnosticsType) = &PyType_Type;
if (PyType_Ready(&diagnosticsType) == -1) goto exit;
@ -1084,6 +1088,7 @@ INIT_MODULE(_psycopg)(void)
PyModule_AddObject(module, "Column", (PyObject*)&columnType);
PyModule_AddObject(module, "Notify", (PyObject*)&notifyType);
PyModule_AddObject(module, "Xid", (PyObject*)&xidType);
PyModule_AddObject(module, "ConnectionInfo", (PyObject*)&connInfoType);
PyModule_AddObject(module, "Diagnostics", (PyObject*)&diagnosticsType);
PyModule_AddObject(module, "AsIs", (PyObject*)&asisType);
PyModule_AddObject(module, "Binary", (PyObject*)&binaryType);

View File

@ -490,7 +490,7 @@ sources = [
'replication_connection_type.c',
'replication_cursor_type.c',
'replication_message_type.c',
'diagnostics_type.c', 'error_type.c',
'diagnostics_type.c', 'error_type.c', 'conninfo_type.c',
'lobject_int.c', 'lobject_type.c',
'notify_type.c', 'xid_type.c',
@ -508,7 +508,7 @@ depends = [
'replication_connection.h',
'replication_cursor.h',
'replication_message.h',
'notify.h', 'pqpath.h', 'xid.h', 'column.h',
'notify.h', 'pqpath.h', 'xid.h', 'column.h', 'conninfo.h',
'libpq_support.h', 'win32_support.h',
'adapter_asis.h', 'adapter_binary.h', 'adapter_datetime.h',

View File

@ -1682,17 +1682,14 @@ while True:
self.assert_(not err, err)
class TestConnectionProps(ConnectingTestCase):
class TestConnectionInfo(ConnectingTestCase):
def test_host(self):
self.assertFalse(self.conn.closed)
expected = dbhost if dbhost else "/"
self.assertIn(expected, self.conn.host)
self.assertIn(expected, self.conn.info.host)
def test_host_readonly(self):
self.assertFalse(self.conn.closed)
with self.assertRaises(AttributeError):
self.conn.host = 'override'
self.conn.info.host = 'override'
def test_suite():