-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
BUG: to_sql with datetime.time values with sqlite #11547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@nbonnotte Thanks for working on this! As a quick feedback: I think we will also want this to work in the other direction, so from sql -> python, that you get back |
A quick update @jorisvandenbossche to go the other way around is a bit more tricky, because (if i'm not mistaken) we depend on the sqlite3 connexion provided by the user. Quick recap: in order for sqlite3 to know how to convert data back into the proper Python object, the user need to provide a parameter
Since the dataframe we want to sqlize most likely has names for its columns, I guess we can exclude option 2. For backward compatibility reason, option 3 needs to be kept working, and option 1 is the one we want to implement here. From a very practical point of view, we thus need to have tests for both option 1 and option 3, because we don't know the connection the user will throw at us. That's when some difficulties arise: in
I hope it's just a matter of type conversion, that for some strange reason looks really really weird. I haven't had much time to look precisely onto it yet, but going the other way around (sqlite → python) will definitely demand more work than my initial pull request (python → sqlite). |
@jorisvandenbossche So basically, with the current pull request, the sqlite3 fallback should work exactly as with sqlalchemy. To go further, that is to also provide a converter, would cause the "sqlite3 fallback" to have more features than with sqlalchemy, because then you would be able with the fallback to end up with, say, Am I wrong? And assuming it is still an interesting direction to go, wouldn't it be better to have a new, separate issue, and let this PR close #8341? |
@jorisvandenbossche status of this? |
status of this? |
@jorisvandenbossche Maybe we could let this PR close issue #8341, and start a new issue to go in the other direction (sql -> python) ? What do you think? |
# this will transform time(12,34,56,789) into '12:34:56.000789' | ||
# (this is what sqlalchemy does) | ||
sqlite3.register_adapter(time, lambda _: _.strftime("%H:%M:%S.%f")) | ||
super(self.__class__, self).__init__(*args, **kwargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this work correctly if inherited? You generally want super(SQLiteTable, self).__init__(*args, **kwargs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, thanks
@nbonnotte yes, certainly a good idea to limit it here to pandas->sql! |
Great. And it's all green! \o/ |
def __init__(self, *args, **kwargs): | ||
# GH 8341 | ||
# register an adapter callable for datetime.time object | ||
# if we're here, it means we have sqlite3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sqlite3 is standard library, so the comment can be removed I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, thanks
Pull request updated and green |
def __init__(self, *args, **kwargs): | ||
# GH 8341 | ||
# register an adapter callable for datetime.time object | ||
import sqlite3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this standard practice to do this in the init? (rather than at a class level)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the idea is to only have this adapter being registered if you actually use pandas with to_sql
, not if you just import pandas to do other things (as this changes the behaviour of sqlite).
But actually, we should maybe test how this possibly interferes with sqlalchemy. @nbonnotte Can you test that writing/reading time values with sqlalchemy still works after having run this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nbonnotte did you for @jorisvandenbossche comments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet, I'm a bit busy right now, but I've noted :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done... I think, see the test below
@jorisvandenbossche is it what you had in mind?
if self.flavor == 'sqlite': | ||
self.assertRaises(sqlite3.InterfaceError, sql.to_sql, df, | ||
'test_time', self.conn) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you leave this test here? (but the updated version of course with checking of the output)
@nbonnotte Sorry for the delay, but some comments on the tests |
I've updated the PR taking into account comments from @jorisvandenbossche |
Thanks @nbonnotte |
Ok. If it can be shipped in 0.18.0, all the better — otherwise I'll change the whatsnew again. All green. |
@nbonnotte merged, thanks! |
I'm proposing a solution to #8341
As @jorisvandenbossche suggested, I use a sqlite3 adapter to transform
datetime.time
objects into string (hh:mm:ss.ffffff
, as this what sqlalchemy... I think?)I added a test in the class
_TestSQLApi
, so that the solution is tested with both sqlalchemy and the sqlite3 fallback. Thus, the result should be consistent.