So because of [reasons], I'm looking at overriding the tzinfo classes that are set by pyscopg2. I thought this would be a simple case of overriding tzinfo_factory on the cursor class. However, this doesn't seem to work.
import psycopg2
from psycopg2.extensions import cursor
from psycopg2.tz import FixedOffsetTimezone
class MyFixedOffsetTimezone(FixedOffsetTimezone):
pass
class MyCursorFactory(cursor):
tzinfo_factory = MyFixedOffsetTimezone
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
conn = psycopg2.connect('', cursor_factory=MyCursorFactory)
cursor = conn.cursor()
cursor.execute("select now()")
results = cursor.fetchall()
print(results[0][0].tzinfo)
print(results[0][0].tzinfo.__class__)
Will still give you
$ python3 example.py
psycopg2.tz.FixedOffsetTimezone(offset=60, name=None)
<class 'psycopg2.tz.FixedOffsetTimezone'>
Is this a result of my fundamental misunderstanding of how the C implementation's members and the higher level python interact? (or am I being a complete pleb?) versions: python 3.5.2 tested in psycopg2 2.6.2 and 2.7.1
I've trawled through the code, and it does seem to be referencing tzinfo_factory on the cursor (psycopg/typecast_datetime.c:typecast_PYDATETIME_cast line 140 # 2.7.1)
tzinfo_factory = ((cursorObject *)curs)->tzinfo_factory;
You have to pass the cursor_factory=... and assign MyFixedOffsetTimezone to MyCursorFactory:
class MyFixedOffsetTimezone(FixedOffsetTimezone):
pass
class MyCursorFactory(cursor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tzinfo_factory = MyFixedOffsetTimezone
conn = psycopg2.connect('...')
cursor = conn.cursor(cursor_factory=MyCursorFactory)
cursor.execute("select now()")
results = cursor.fetchall()
print(results[0][0].tzinfo)
print(results[0][0].tzinfo.__class__)
returns:
psycopg2.tz.FixedOffsetTimezone(offset=120, name=None)
<class '__main__.MyFixedOffsetTimezone'>
Related
I am using Python 3.6, under the Pycharm environment.
I would like to mock sqlite3.connect. For example in TestDatabase (see below), I would like test_sqlite3_connect to return the string connection rather than an actual self.db_conn object.
I have tried it, but that does not work.
class Database:
def __init__(self, conn_string):
self.db_conn = sqlite3.connect(conn_string, check_same_thread=False)
self.db_conn.row_factory = self.dict_factory
class TestDatabase(unittest.TestCase):
def setUp(self):
self.db_conn = db.Database('videodetector.db')
def test_sqlite3_connect_success(self):
sqlite3.connect = MagicMock(return_value='connection succeeded')
db_conn=db.Database('videodetector.db')
sqlite3.connect.assert_called_with('videodetector.db')
self.assertEqual(db_conn, 'connection succeeded')
Using Python 2.7.12 and package cx_Oracle I'm trying to create an extended class of the what the package call OracleCursor. I simply want to inherit the methods from the superclass and extend with some custom methods.
First I get the OracleCursor by
import cx_Oracle
conn = cx_Oracle.connect(username, password, dsn)
cursor = conn.cursor()
and I then have the following
>>> type(cursor)Out[6]:
OracleCursor
>>> isinstance(cursor, cx_Oracle.Cursor)
True
One would think that it is achieved by
class ExtendedCursor(cx_Oracle.Cursor):
def hello_world(self):
print('Hello world')
extended = ExtendedCursor(cursor)
but I get TypeError: argument 1 must be cx_Oracle.Connection, not OracleCursor. To me that error doesn't make sense. Also, I can't use OracleCursor as my superclass since it isn't recognized as a class.
The cursor is returned from the Connection object. You need to create a custom connection that returns your ExtendedCursor.
import cx_Oracle as cxo
class MyCursor(cxo.Cursor):
def helloWorld(self):
print "helloWorld"
class MyConnection(cxo.Connection):
def cursor(self):
return MyCursor(self)
if __name__ == '__main__':
conStr = '<user>/<password>#127.0.0.1:1521/xe'
db = MyConnection(conStr)
c = db.cursor()
print c
c.execute('select 1+1 from dual')
print(c.fetchall())
c.helloWorld()
returns:
<__main__.MyCursor on <__main__.MyConnection to ...#127.0.0.1:1521/xe>>
[(2,)]
helloWorld
I'm using python3.4 to interact with oracle(11g)/sql developer.
Is it true that cx_Oracle could not deal with sqlPlus statements? It seems that the page https://sourceforge.net/p/cx-oracle/mailman/message/2932119/ said so.
So how could we execute 'spool' command by python?
The code:
import cx_Oracle
db_conn = cx_Oracle.connect(...)
cursor = db_conn.cursor()
cursor.execute('spool C:\\Users\Administrator\Desktop\mycsv.csv')
...
the error: cx_Oracle.DatabaseError: ORA-00900:
The "spool" command is very specific to SQL*Plus and is not available in cx_Oracle or any other application that uses the OCI (Oracle Call Interface). You can do something similar, however, without too much trouble.
You can create your own Connection class subclassed from cx_Oracle.Connection and your own Cursor class subclassed from cx_Oracle.Cursor that would perform any logging and have a special command "spool" that would turn it on and off at will. Something like this:
class Connection(cx_Oracle.Connection):
def __init__(self, *args, **kwargs):
self.spoolFile = None
return super(Connection, self).__init__(*args, **kwargs)
def cursor(self):
return Cursor(self)
def spool(self, fileName):
self.spoolFile = open(fileName, "w")
class Cursor(cx_Oracle.Cursor):
def execute(self, statement, args):
result = super(Cursor, self).execute(statement, args)
if self.connection.spoolFile is not None:
self.connection.spoolFile.write("Headers for query\n")
self.connection.spoolFile.write("use cursor.description")
def fetchall(self):
rows = super(Cursor, self).fetchall()
if self.connection.spoolFile is not None:
for row in rows:
self.connection.spoolFile.write("row details")
That should give you some idea on where to go with this.
I am working on a simple convenience class to use with the with operator so that I can establish exclusive access to a sqlite3 database for a extended writing session in a concurrent system.
Here is the class:
import sqlite3 as sql
class ExclusiveSqlConnection(object):
"""meant to be used with a with statement to ensure proper closure"""
def __enter__(self, path):
self.con = sql.connect(path, isolation_level = "EXCLUSIVE")
self.con.execute("BEGIN EXCLUSIVE")
self.cur = self.con.cursor()
return self
def __exit__(self):
self.con.commit()
self.con.close()
However, when I run this I get the error:
with sql_lib.ExclusiveSqlConnection(self.output) as c:
TypeError: object.__new__() takes no parameters
The constructor (__init__ method) for your ExclusiveSqlConnection needs to take a path parameter.
On the other hand, __enter__ takes no parameter other than self.
import sqlite3 as sql
class ExclusiveSqlConnection(object):
"""meant to be used with a with statement to ensure proper closure"""
def __init__(self, path):
self.path = path
def __enter__(self):
self.con = sql.connect(self.path, isolation_level = "EXCLUSIVE")
self.con.execute("BEGIN EXCLUSIVE")
self.cur = self.con.cursor()
return self
def __exit__(self, exception_type, exception_val, trace):
self.con.commit()
self.con.close()
I have problem with using class instance in Python.
Ive created a new class ora which inherit connect class from cx_Oracle package.
When I try tu run this code I recive information
File "pyt.py", line 12, in myquery
ora.myConnect.cursor()
AttributeError: 'NoneType' object has no attribute 'cursor'
So Python cannote recognize that in ora.myConnect is stored reference to instance.
I dont know what can be reason of this error and what its wrong with code.
from cx_Oracle import connect
class ora(connect):
myConnect = None
def __init__(self,connstr):
ora.myConnect = connect.__init__(self,connstr)
def myquery(self):
ora.myConnect.cursor()
ora.myConnect.cursor.execute("SELECT * FROM table")
ora.myConnect.cursor.close()
connstr = 'user/passwd#host:port/sid'
connection = ora(connstr)
connection.myquery()
connection.close()
EDIT
Ive tried to replace ora to self but still Python dont have access to instance
from cx_Oracle import connect
class ora(connect):
myConnect = None
def __init__(self,connstr):
self.myConnect = connect.__init__(self,connstr)
def myquery(self):
self.myConnect.cursor()
self.myConnect.cursor.execute("SELECT * FROM table")
self.myConnect.cursor.close()
Error:
self.myConnect.cursor()
AttributeError: 'NoneType' object has no attribute 'cursor'
EDIT2
This code works without OOP, for me self.myConnect sholud reference to object instance and this object should contain method cursor()
import cx_oracle
connstr = 'user/passwd#host:port/sid'
connection = cx_oracle.connect(connstr)
cursor = connection.cursor()
cursor.execute("SELECT * FROM table")
cursor.close()
connection.close()
It seems like you want self:
class ora(connect):
myConnect = None
def __init__(self, connstr):
self.myConnect = connect.__init__(self, connstr)
# ...
ora is the name of the class, not the instance.
Update Try the following:
from cx_Oracle import connect
class ora:
myConnect = None
def __init__(self, connstr):
self.myConnect = connect(connstr)
def myquery(self):
self.myConnect.cursor()
self.myConnect.cursor.execute("SELECT * FROM table")
self.myConnect.cursor.close()
Why do you want self.myConnect to refer to the connect instance? That's a complete misunderstanding of OOP. The ora instance is the connect instance. self.cursor is where you find the cursor.
Here's how your code should look:
class ora(connect):
def __init__(self,connstr):
super(ora, self).__init__(connstr)
def myquery(self):
self.cursor.execute("SELECT * FROM table")
self.cursor.close()
In any case, __init__ must never return anything, so setting self.myConnect to the return value will always result in it being bound to None.