Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

support django 1.4 #106

Closed
wants to merge 12 commits into from
@CMGS

django 1.4 use some MySQLdb internal functions and wrapped the converters like convert_datetime. in that case I add functions and refactor converters make it similar to MySQLdb's.

@petehunt

Just import this at the top

@petehunt

nit: space before pass

@petehunt
Owner

Cool this is looking good, but can you add some simple tests for these methods so we are sure we don't regress in the future? Thanks!

@CMGS

Ok, i will do asap.

@CMGS

I add simple tests for Thing2Literal and connection.select_db, other changes could pass all current unit tests.

@petehunt

e...yes..sorry, seems when i commit it i pressed wrong key..

@gabriel-samfira

Any news on this? PyMySQL still throws and error when replacing MySQLdb in Django 1.4.

@CMGS

@gabriel-samfira i think u can use my fork...it seems work well in my project : )

@gabriel-samfira

@CMGS Yep, thanks! Already using it and it works great :). Can't have mysql connections lock up gevent, now cat we? :P

@gabriel-samfira

@CMGS It apears to have a memory leak somewhere. I have a long running script that uses the Django ORM. It grows in memory with each run. This should not be a problem with the normal Django request/response flow, but you might want to have a look. I'm not sure if its a Django or a pymysql issue. I just switched back to Django 1.3 with PyMysql and all is fine.

I was using Django 1.4 with PyMySQL from your fork. DEBUG was False.

@CMGS
@gabriel-samfira

It looks good with Django 1.3. I think it may be some change in django itself. It was not meant to be used in a long running application. In a normal request/response scenario it works as expected. I'll have to do some digging.

I'm using the Django ORM in a daemon to keep track of tasks I send out to a bunch of servers. Replies come back through RabbitMQ and I check the database for the ID of the task. It was a shortcut so I could share a bunch of code for the daemon and site. Sorry for the lack of due diligence before posting :).

@timotta

Worked for me. Any plans for integration?

@christian-oudard

I would also like to use this. Can I put in another vote for pulling this in?

@TTimo

Running into these problems with Django 1.5 as well (Thing2Literal). +1 for having fixes go into mainline PyMySQL

@piotrbulinski

+1 for Django 1.5 compatibility (Thing2Literal)

@EvilClosetMonkey

+1 for master integration. (Thing2Literal)

@alekseyr

Justin, thank you for fix.

@kcolton

+1 on Thing2Literal Django 1.5.1 compat problems

@Morpho

+1 would love to see this in master

@elee-nst

Another vote for integrating this pull request with master (to resolve the Thing2Literal issue with Django 1.5).

@boxed

Would really like this!

@methane
Owner

Supporting Django is nice.
But I feel PyMySQL's converters are little mess.

Please wait...

@methane
Owner

Refactoring is done by #160.
Django support should be reimplemented.

@methane methane closed this
@TTimo

\o/ .. thanks @methane

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 24, 2012
  1. @CMGS

    add miss func

    CMGS authored
  2. @CMGS

    support mysqldb single value

    CMGS authored
  3. @CMGS

    add ignore

    CMGS authored
Commits on Apr 25, 2012
  1. @CMGS

    refactor converts

    CMGS authored
  2. @CMGS

    clean

    CMGS authored
  3. @CMGS

    bug fix

    CMGS authored
Commits on May 14, 2012
  1. @CMGS

    adjust

    CMGS authored
  2. @CMGS

    add test

    CMGS authored
  3. @CMGS

    typo..sorry

    CMGS authored
Commits on Jun 18, 2012
  1. @CMGS
  2. @CMGS
Commits on Oct 22, 2012
  1. @CMGS
This page is out of date. Refresh to see the latest.
View
1  .gitignore
@@ -3,3 +3,4 @@ __pycache__
py3k
dist
PyMySQL.egg-info
+build
View
24 pymysql/connections.py
@@ -15,10 +15,12 @@
except ImportError:
SSL_ENABLED = False
+import traceback
import struct
import sys
import os
import ConfigParser
+from functools import partial
try:
import cStringIO as StringIO
@@ -197,6 +199,7 @@ def defaulterrorhandler(connection, cursor, errorclass, errorvalue):
del connection
if not issubclass(errorclass, Error):
+ traceback.print_exc()
raise Error(errorclass, errorvalue)
else:
raise errorclass, errorvalue
@@ -599,7 +602,6 @@ def _config(key, default):
self.commit()
-
def close(self):
''' Send the quit message and close the socket '''
if self.socket is None:
@@ -645,6 +647,10 @@ def rollback(self):
exc,value,tb = sys.exc_info()
self.errorhandler(None, exc, value)
+ def select_db(self, db):
+ self.db = db
+ self.query("USE %s" % db)
+
def escape(self, obj):
''' Escape whatever value you pass to it '''
return escape_item(obj, self.charset)
@@ -976,7 +982,7 @@ def init_unbuffered_query(self):
else:
self.field_count = byte2int(first_packet.read(1))
self._get_descriptions()
-
+
# Apparently, MySQLdb picks this number because it's the maximum
# value of a 64bit unsigned integer. Since we're emulating MySQLdb,
# we set it to this instead of None, which would be preferred.
@@ -1006,7 +1012,7 @@ def _read_result_packet(self, first_packet):
def _read_rowdata_packet_unbuffered(self):
# Check if in an active query
if self.unbuffered_active == False: return
-
+
# EOF
packet = self.connection.read_packet()
if self._check_packet_is_eof(packet):
@@ -1022,7 +1028,11 @@ def _read_rowdata_packet_unbuffered(self):
converter = self.connection.decoders[field.type_code]
if DEBUG: print "DEBUG: field=%s, converter=%s" % (field, converter)
if data != None:
- converted = converter(self.connection, field, data)
+ if converter.func_name == 'convert_characters':
+ converter = partial(converter, self.connection, field)
+ elif not isinstance(data, unicode):
+ data = data.decode(self.connection.charset)
+ converted = converter(data)
row.append(converted)
self.affected_rows = 1
@@ -1056,7 +1066,11 @@ def _read_rowdata_packet(self):
converter = self.connection.decoders[field.type_code]
if DEBUG: print "DEBUG: field=%s, converter=%s" % (field, converter)
if data != None:
- converted = converter(self.connection, field, data)
+ if converter.func_name == 'convert_characters':
+ converter = partial(converter, self.connection, field)
+ elif not isinstance(data, unicode):
+ data = data.decode(self.connection.charset)
+ converted = converter(data)
row.append(converted)
rows.append(tuple(row))
View
37 pymysql/converters.py
@@ -100,7 +100,10 @@ def escape_date(obj):
def escape_struct_time(obj):
return escape_datetime(datetime.datetime(*obj[:6]))
-def convert_datetime(connection, field, obj):
+def Thing2Literal(o, d):
+ return "'%s'" % escape_string(str(o))
+
+def convert_datetime(obj):
"""Returns a DATETIME or TIMESTAMP column value as a datetime object:
>>> datetime_or_None('2007-02-25 23:06:20')
@@ -116,22 +119,20 @@ def convert_datetime(connection, field, obj):
True
"""
- if not isinstance(obj, unicode):
- obj = obj.decode(connection.charset)
if ' ' in obj:
sep = ' '
elif 'T' in obj:
sep = 'T'
else:
- return convert_date(connection, field, obj)
+ return convert_date(obj)
try:
ymd, hms = obj.split(sep, 1)
return datetime.datetime(*[ int(x) for x in ymd.split('-')+hms.split(':') ])
except ValueError:
- return convert_date(connection, field, obj)
+ return convert_date(obj)
-def convert_timedelta(connection, field, obj):
+def convert_timedelta(obj):
"""Returns a TIME column as a timedelta object:
>>> timedelta_or_None('25:06:17')
@@ -166,7 +167,7 @@ def convert_timedelta(connection, field, obj):
except ValueError:
return None
-def convert_time(connection, field, obj):
+def convert_time(obj):
"""Returns a TIME column as a time object:
>>> time_or_None('15:06:17')
@@ -199,7 +200,7 @@ def convert_time(connection, field, obj):
except ValueError:
return None
-def convert_date(connection, field, obj):
+def convert_date(obj):
"""Returns a DATE column as a date object:
>>> date_or_None('2007-02-26')
@@ -214,13 +215,11 @@ def convert_date(connection, field, obj):
"""
try:
- if not isinstance(obj, unicode):
- obj = obj.decode(connection.charset)
return datetime.date(*[ int(x) for x in obj.split('-', 2) ])
except ValueError:
return None
-def convert_mysql_timestamp(connection, field, timestamp):
+def convert_mysql_timestamp(timestamp):
"""Convert a MySQL TIMESTAMP to a Timestamp object.
MySQL >= 4.1 returns TIMESTAMP in the same format as DATETIME:
@@ -241,11 +240,8 @@ def convert_mysql_timestamp(connection, field, timestamp):
True
"""
- if not isinstance(timestamp, unicode):
- timestamp = timestamp.decode(connection.charset)
-
if timestamp[4] == '-':
- return convert_datetime(connection, field, timestamp)
+ return convert_datetime(timestamp)
timestamp += "0"*(14-len(timestamp)) # padding
year, month, day, hour, minute, second = \
int(timestamp[:4]), int(timestamp[4:6]), int(timestamp[6:8]), \
@@ -258,7 +254,7 @@ def convert_mysql_timestamp(connection, field, timestamp):
def convert_set(s):
return set(s.split(","))
-def convert_bit(connection, field, b):
+def convert_bit(b):
#b = "\x00" * (8 - len(b)) + b # pad w/ zeroes
#return struct.unpack(">Q", b)[0]
#
@@ -280,13 +276,13 @@ def convert_characters(connection, field, data):
data = data.encode(connection.charset)
return data
-def convert_int(connection, field, data):
+def convert_int(data):
return int(data)
-def convert_long(connection, field, data):
+def convert_long(data):
return long(data)
-def convert_float(connection, field, data):
+def convert_float(data):
return float(data)
encoders = {
@@ -342,8 +338,7 @@ def convert_float(connection, field, data):
try:
# python version > 2.3
from decimal import Decimal
- def convert_decimal(connection, field, data):
- data = data.decode(connection.charset)
+ def convert_decimal(data):
return Decimal(data)
decoders[FIELD_TYPE.DECIMAL] = convert_decimal
decoders[FIELD_TYPE.NEWDECIMAL] = convert_decimal
View
11 pymysql/tests/test_basic.py
@@ -1,3 +1,4 @@
+from pymysql.converters import Thing2Literal
from pymysql.tests import base
from pymysql import util
@@ -55,6 +56,9 @@ def test_dict(self):
finally:
c.execute("drop table test_dict")
+ def test_thing2literal(self):
+ self.assertEqual('2' == Thing2Literal(2, {}))
+
def test_string(self):
conn = self.connections[0]
c = conn.cursor()
@@ -167,6 +171,13 @@ class TestCursor(base.PyMySQLTestCase):
#
# self.assertEqual(r, c.description)
+ def test_select_db(self):
+ conn = self.connections[0]
+ try:
+ conn.select_db('test_pymysql')
+ finally:
+ pass
+
def test_fetch_no_result(self):
""" test a fetchone() with no rows """
conn = self.connections[0]
Something went wrong with that request. Please try again.