Remove tornado.database, which is now distributed separately.

This commit is contained in:
Ben Darnell 2012-09-16 14:02:49 -07:00
parent 4044f96c96
commit 186e947112
15 changed files with 13 additions and 281 deletions

View File

@ -21,7 +21,7 @@ matrix:
install:
- if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install --use-mirrors simplejson unittest2; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --use-mirrors unittest2; fi
- if [[ $FULL == 'true' ]]; then sudo apt-get install librtmp-dev; pip install --use-mirrors MySQL-python pycurl; fi
- if [[ $FULL == 'true' ]]; then sudo apt-get install librtmp-dev; pip install --use-mirrors pycurl; fi
- if [[ $FULL == 'true' && $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install --use-mirrors twisted==11.0.0 'zope.interface<4.0'; fi
- if [[ $FULL == 'true' && $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --use-mirrors twisted==11.0.0; fi
- if [[ $FULL == 'true' && $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors twisted==12.0.0; fi

View File

@ -16,6 +16,10 @@ need to set up MySQL and the database schema for the demo to run.
can run "apt-get install mysql". Under OS X you can download the
MySQL PKG file from http://dev.mysql.com/downloads/mysql/
3. Install Python prerequisites
Install the packages MySQL-python and torndb (e.g. using pip or easy_install)
3. Connect to MySQL and create a database and user for the blog.
Connect to MySQL as a user that can create databases and users:
@ -51,7 +55,7 @@ need to set up MySQL and the database schema for the demo to run.
authentication.
Currently the first user to connect will automatically be given the
ability to create and edit posts.
ability to create and edit posts.
Once you've created one blog post, subsequent users will not be
prompted to sign in.

View File

@ -17,8 +17,8 @@
import markdown
import os.path
import re
import torndb
import tornado.auth
import tornado.database
import tornado.httpserver
import tornado.ioloop
import tornado.options
@ -58,7 +58,7 @@ class Application(tornado.web.Application):
tornado.web.Application.__init__(self, handlers, **settings)
# Have one global connection to the blog DB across all handlers
self.db = tornado.database.Connection(
self.db = torndb.Connection(
host=options.mysql_host, database=options.mysql_database,
user=options.mysql_user, password=options.mysql_password)
@ -152,7 +152,7 @@ class AuthLoginHandler(BaseHandler, tornado.auth.GoogleMixin):
self.get_authenticated_user(self.async_callback(self._on_auth))
return
self.authenticate_redirect()
def _on_auth(self, user):
if not user:
raise tornado.web.HTTPError(500, "Google auth failed")

View File

@ -1,7 +1,6 @@
# Frozen pip requirements for tools used in the development of tornado
# Tornado's optional dependencies
MySQL-python==1.2.3
Twisted==12.1.0
pycurl==7.19.0

View File

@ -33,7 +33,6 @@ def import_everything():
# import tornado.auth
# import tornado.autoreload
# import tornado.curl_httpclient # depends on pycurl
# import tornado.database # depends on MySQLdb
import tornado.escape
# import tornado.httpclient
# import tornado.httpserver
@ -53,7 +52,7 @@ def import_everything():
import tornado.web
# import tornado.websocket
import tornado.wsgi
def all():
return unittest.defaultTestLoader.loadTestsFromNames(TEST_MODULES)
@ -72,4 +71,3 @@ def main():
if __name__ == '__main__':
main()

View File

@ -12,7 +12,6 @@ apt-get update
APT_PACKAGES="
python-pip
python-dev
libmysqlclient-dev
libcurl4-openssl-dev
python-software-properties
"
@ -40,7 +39,6 @@ apt-get -y install $DEADSNAKES_PACKAGES
PIP_PACKAGES="
virtualenv
tox
MySQL-python
pycurl
twisted
"

View File

@ -15,7 +15,6 @@ deps =
[testenv:py25-full]
basepython = python2.5
deps =
MySQL-python
pycurl
simplejson
twisted==11.0.0
@ -27,7 +26,6 @@ deps = unittest2
[testenv:py26-full]
deps =
MySQL-python
pycurl
twisted==11.0.0
unittest2
@ -35,6 +33,5 @@ deps =
[testenv:py27-full]
basepython = python2.7
deps =
MySQL-python
pycurl
twisted==11.0.0

View File

@ -12,7 +12,6 @@ apt-get update
APT_PACKAGES="
python-pip
python-dev
libmysqlclient-dev
libcurl4-openssl-dev
python-software-properties
"
@ -38,7 +37,6 @@ apt-get -y install $DEADSNAKES_PACKAGES
PIP_PACKAGES="
virtualenv
tox
MySQL-python
pycurl
twisted
"

View File

@ -15,7 +15,6 @@ deps =
[testenv:py25-full]
basepython = python2.5
deps =
MySQL-python
pycurl
simplejson
twisted==11.0.0
@ -29,6 +28,5 @@ deps = unittest2
[testenv:py27-full]
basepython = python2.7
deps =
MySQL-python
pycurl
twisted==11.0.0

View File

@ -1,239 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""A lightweight wrapper around MySQLdb."""
from __future__ import absolute_import, division, with_statement
import copy
import itertools
import time
from tornado.log import gen_log
try:
import MySQLdb.constants
import MySQLdb.converters
import MySQLdb.cursors
except ImportError:
# If MySQLdb isn't available this module won't actually be useable,
# but we want it to at least be importable (mainly for readthedocs.org,
# which has limitations on third-party modules)
MySQLdb = None
class Connection(object):
"""A lightweight wrapper around MySQLdb DB-API connections.
The main value we provide is wrapping rows in a dict/object so that
columns can be accessed by name. Typical usage::
db = database.Connection("localhost", "mydatabase")
for article in db.query("SELECT * FROM articles"):
print article.title
Cursors are hidden by the implementation, but other than that, the methods
are very similar to the DB-API.
We explicitly set the timezone to UTC and the character encoding to
UTF-8 on all connections to avoid time zone and encoding errors.
"""
def __init__(self, host, database, user=None, password=None,
max_idle_time=7 * 3600):
self.host = host
self.database = database
self.max_idle_time = max_idle_time
args = dict(conv=CONVERSIONS, use_unicode=True, charset="utf8",
db=database, init_command='SET time_zone = "+0:00"',
sql_mode="TRADITIONAL")
if user is not None:
args["user"] = user
if password is not None:
args["passwd"] = password
# We accept a path to a MySQL socket file or a host(:port) string
if "/" in host:
args["unix_socket"] = host
else:
self.socket = None
pair = host.split(":")
if len(pair) == 2:
args["host"] = pair[0]
args["port"] = int(pair[1])
else:
args["host"] = host
args["port"] = 3306
self._db = None
self._db_args = args
self._last_use_time = time.time()
try:
self.reconnect()
except Exception:
gen_log.error("Cannot connect to MySQL on %s", self.host,
exc_info=True)
def __del__(self):
self.close()
def close(self):
"""Closes this database connection."""
if getattr(self, "_db", None) is not None:
self._db.close()
self._db = None
def reconnect(self):
"""Closes the existing database connection and re-opens it."""
self.close()
self._db = MySQLdb.connect(**self._db_args)
self._db.autocommit(True)
def iter(self, query, *parameters):
"""Returns an iterator for the given query and parameters."""
self._ensure_connected()
cursor = MySQLdb.cursors.SSCursor(self._db)
try:
self._execute(cursor, query, parameters)
column_names = [d[0] for d in cursor.description]
for row in cursor:
yield Row(zip(column_names, row))
finally:
cursor.close()
def query(self, query, *parameters):
"""Returns a row list for the given query and parameters."""
cursor = self._cursor()
try:
self._execute(cursor, query, parameters)
column_names = [d[0] for d in cursor.description]
return [Row(itertools.izip(column_names, row)) for row in cursor]
finally:
cursor.close()
def get(self, query, *parameters):
"""Returns the first row returned for the given query."""
rows = self.query(query, *parameters)
if not rows:
return None
elif len(rows) > 1:
raise Exception("Multiple rows returned for Database.get() query")
else:
return rows[0]
# rowcount is a more reasonable default return value than lastrowid,
# but for historical compatibility execute() must return lastrowid.
def execute(self, query, *parameters):
"""Executes the given query, returning the lastrowid from the query."""
return self.execute_lastrowid(query, *parameters)
def execute_lastrowid(self, query, *parameters):
"""Executes the given query, returning the lastrowid from the query."""
cursor = self._cursor()
try:
self._execute(cursor, query, parameters)
return cursor.lastrowid
finally:
cursor.close()
def execute_rowcount(self, query, *parameters):
"""Executes the given query, returning the rowcount from the query."""
cursor = self._cursor()
try:
self._execute(cursor, query, parameters)
return cursor.rowcount
finally:
cursor.close()
def executemany(self, query, parameters):
"""Executes the given query against all the given param sequences.
We return the lastrowid from the query.
"""
return self.executemany_lastrowid(query, parameters)
def executemany_lastrowid(self, query, parameters):
"""Executes the given query against all the given param sequences.
We return the lastrowid from the query.
"""
cursor = self._cursor()
try:
cursor.executemany(query, parameters)
return cursor.lastrowid
finally:
cursor.close()
def executemany_rowcount(self, query, parameters):
"""Executes the given query against all the given param sequences.
We return the rowcount from the query.
"""
cursor = self._cursor()
try:
cursor.executemany(query, parameters)
return cursor.rowcount
finally:
cursor.close()
def _ensure_connected(self):
# Mysql by default closes client connections that are idle for
# 8 hours, but the client library does not report this fact until
# you try to perform a query and it fails. Protect against this
# case by preemptively closing and reopening the connection
# if it has been idle for too long (7 hours by default).
if (self._db is None or
(time.time() - self._last_use_time > self.max_idle_time)):
self.reconnect()
self._last_use_time = time.time()
def _cursor(self):
self._ensure_connected()
return self._db.cursor()
def _execute(self, cursor, query, parameters):
try:
return cursor.execute(query, parameters)
except OperationalError:
gen_log.error("Error connecting to MySQL on %s", self.host)
self.close()
raise
class Row(dict):
"""A dict that allows for object-like property access syntax."""
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
if MySQLdb is not None:
# Fix the access conversions to properly recognize unicode/binary
FIELD_TYPE = MySQLdb.constants.FIELD_TYPE
FLAG = MySQLdb.constants.FLAG
CONVERSIONS = copy.copy(MySQLdb.converters.conversions)
field_types = [FIELD_TYPE.BLOB, FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING]
if 'VARCHAR' in vars(FIELD_TYPE):
field_types.append(FIELD_TYPE.VARCHAR)
for field_type in field_types:
CONVERSIONS[field_type] = [(FLAG.BINARY, str)] + CONVERSIONS[field_type]
# Alias some common MySQL exceptions
IntegrityError = MySQLdb.IntegrityError
OperationalError = MySQLdb.OperationalError

View File

@ -10,7 +10,6 @@ class ImportTest(unittest.TestCase):
import tornado.auth
import tornado.autoreload
# import tornado.curl_httpclient # depends on pycurl
# import tornado.database # depends on MySQLdb
import tornado.escape
import tornado.httpclient
import tornado.httpserver
@ -42,14 +41,6 @@ class ImportTest(unittest.TestCase):
else:
import tornado.curl_httpclient
def test_import_mysqldb(self):
try:
import MySQLdb
except ImportError:
pass
else:
import tornado.database
def test_import_twisted(self):
try:
import twisted

10
tox.ini
View File

@ -7,9 +7,7 @@
# less thorough.
#
# On my macports-based setup, the environment variable
# ARCHFLAGS='-arch x86_64' must be set when building pycurl, and a
# symlink from mysql_config to mysql_config5 must exist when building
# MySQL-python.
# ARCHFLAGS='-arch x86_64' must be set when building pycurl.
[tox]
# "-full" variants include optional dependencies, to ensure
# that things work both in a bare install and with all the extras.
@ -35,7 +33,6 @@ deps =
[testenv:py25-full]
basepython = python2.5
deps =
MySQL-python
pycurl
simplejson
# twisted is dropping python 2.5 support in 12.2.0
@ -53,7 +50,6 @@ deps = unittest2
[testenv:py26-full]
basepython = python2.6
deps =
MySQL-python
pycurl
twisted==11.0.0
unittest2
@ -61,7 +57,6 @@ deps =
[testenv:py27-full]
basepython = python2.7
deps =
MySQL-python
pycurl
twisted>=12.0.0
@ -71,7 +66,6 @@ deps =
# this flag controls which client all the other tests use.
basepython = python2.7
deps =
MySQL-python
pycurl
twisted>=11.1.0
commands = python -m tornado.test.runtests --httpclient=tornado.curl_httpclient.CurlAsyncHTTPClient {posargs:}
@ -83,7 +77,6 @@ commands = python -m tornado.test.runtests --httpclient=tornado.curl_httpclient.
# run this configuration there.
basepython = pypy
deps =
MySQL-python
twisted>=12.1.0
# In python 3, opening files in text mode uses a system-dependent encoding by
@ -113,7 +106,6 @@ basepython = python3.3
[testenv:py27-opt]
basepython = python2.7
deps =
MySQL-python
pycurl
twisted>=12.0.0
commands = python -O -m tornado.test.runtests {posargs:}

View File

@ -1,5 +0,0 @@
``tornado.database`` --- Simple MySQL client wrapper
====================================================
.. automodule:: tornado.database
:members:

View File

@ -4,7 +4,6 @@ Integration with other services
.. toctree::
auth
database
twisted
websocket
wsgi

View File

@ -33,3 +33,5 @@ In progress
* New function `tornado.testing.bind_unused_port` both chooses a port
and binds a socket to it, so there is no risk of another process
using the same port. ``get_unused_port`` is now deprecated.
* The `tornado.database` module has been removed. It is now available
as a separate package, `torndb <https://github.com/bdarnell/torndb>`_